Commit b9ac5a14 by samrobinson Committed by Oliver Woodman

Implement a DefaultMediaDescriptionAdapter that uses MediaMetadata.

PiperOrigin-RevId: 384681659
parent 65124632
......@@ -37,6 +37,9 @@
These methods are all overrides and are already deprecated on `Player`
and the respective `ExoPlayer` component classes (since 2.14.0).
* Rename `Player.EventFlags` IntDef to `Player.Event`.
* Add a `DefaultMediaDescriptionAdapter` for the
`PlayerNotificationManager`, that makes use of the `Player`
`MediaMetadata` to populate the notification fields.
* Remove deprecated symbols:
* Remove `Player.getPlaybackError`. Use `Player.getPlayerError` instead.
* Remove `Player.getCurrentTag`. Use `Player.getCurrentMediaItem` and
......
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.ui;
import android.app.PendingIntent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.ui.PlayerNotificationManager.BitmapCallback;
import com.google.android.exoplayer2.ui.PlayerNotificationManager.MediaDescriptionAdapter;
/**
* Default implementation of {@link MediaDescriptionAdapter}.
*
* <p>Uses values from the {@link Player#getMediaMetadata() player mediaMetadata} to populate the
* notification.
*/
public final class DefaultMediaDescriptionAdapter implements MediaDescriptionAdapter {
@Nullable private final PendingIntent pendingIntent;
/**
* Creates a default {@link MediaDescriptionAdapter}.
*
* @param pendingIntent The {@link PendingIntent} to be returned from {@link
* #createCurrentContentIntent(Player)}, or null if no intent should be fired.
*/
public DefaultMediaDescriptionAdapter(@Nullable PendingIntent pendingIntent) {
this.pendingIntent = pendingIntent;
}
@Override
public CharSequence getCurrentContentTitle(Player player) {
@Nullable CharSequence displayTitle = player.getMediaMetadata().displayTitle;
if (!TextUtils.isEmpty(displayTitle)) {
return displayTitle;
}
@Nullable CharSequence title = player.getMediaMetadata().title;
return title != null ? title : "";
}
@Nullable
@Override
public PendingIntent createCurrentContentIntent(Player player) {
return pendingIntent;
}
@Nullable
@Override
public CharSequence getCurrentContentText(Player player) {
@Nullable CharSequence artist = player.getMediaMetadata().artist;
if (!TextUtils.isEmpty(artist)) {
return artist;
}
return player.getMediaMetadata().albumArtist;
}
@Nullable
@Override
public Bitmap getCurrentLargeIcon(Player player, BitmapCallback callback) {
@Nullable byte[] data = player.getMediaMetadata().artworkData;
if (data == null) {
return null;
}
return BitmapFactory.decodeByteArray(data, /* offset= */ 0, data.length);
}
}
......@@ -19,6 +19,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_WINDO
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_WINDOW;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_WINDOW;
import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_MEDIA_METADATA_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAY_WHEN_READY_CHANGED;
......@@ -307,10 +308,10 @@ public class PlayerNotificationManager {
private final Context context;
private final int notificationId;
private final String channelId;
private final MediaDescriptionAdapter mediaDescriptionAdapter;
@Nullable private NotificationListener notificationListener;
@Nullable private CustomActionReceiver customActionReceiver;
private MediaDescriptionAdapter mediaDescriptionAdapter;
private int channelNameResourceId;
private int channelDescriptionResourceId;
private int channelImportance;
......@@ -325,24 +326,33 @@ public class PlayerNotificationManager {
@Nullable private String groupKey;
/**
* Creates an instance.
*
* @param context The {@link Context}.
* @param notificationId The id of the notification to be posted. Must be greater than 0.
* @param channelId The id of the notification channel.
* @param mediaDescriptionAdapter The {@link MediaDescriptionAdapter} to be used.
* @deprecated Use {@link #Builder(Context, int, String)} instead, then call {@link
* #setMediaDescriptionAdapter(MediaDescriptionAdapter)}.
*/
@Deprecated
public Builder(
Context context,
int notificationId,
String channelId,
MediaDescriptionAdapter mediaDescriptionAdapter) {
this(context, notificationId, channelId);
this.mediaDescriptionAdapter = mediaDescriptionAdapter;
}
/**
* Creates an instance.
*
* @param context The {@link Context}.
* @param notificationId The id of the notification to be posted. Must be greater than 0.
* @param channelId The id of the notification channel.
*/
public Builder(Context context, int notificationId, String channelId) {
checkArgument(notificationId > 0);
this.context = context;
this.notificationId = notificationId;
this.channelId = channelId;
this.mediaDescriptionAdapter = mediaDescriptionAdapter;
channelImportance = NotificationUtil.IMPORTANCE_LOW;
mediaDescriptionAdapter = new DefaultMediaDescriptionAdapter(/* pendingIntent= */ null);
smallIconResourceId = R.drawable.exo_notification_small_icon;
playActionIconResourceId = R.drawable.exo_notification_play;
pauseActionIconResourceId = R.drawable.exo_notification_pause;
......@@ -529,6 +539,18 @@ public class PlayerNotificationManager {
return this;
}
/**
* The {@link MediaDescriptionAdapter} to be queried for the notification contents.
*
* <p>The default is {@link DefaultMediaDescriptionAdapter} with no {@link PendingIntent}
*
* @return This builder.
*/
public Builder setMediaDescriptionAdapter(MediaDescriptionAdapter mediaDescriptionAdapter) {
this.mediaDescriptionAdapter = mediaDescriptionAdapter;
return this;
}
/** Builds the {@link PlayerNotificationManager}. */
public PlayerNotificationManager build() {
if (channelNameResourceId != 0) {
......@@ -539,6 +561,7 @@ public class PlayerNotificationManager {
channelDescriptionResourceId,
channelImportance);
}
return new PlayerNotificationManager(
context,
channelId,
......@@ -1487,7 +1510,8 @@ public class PlayerNotificationManager {
EVENT_PLAYBACK_PARAMETERS_CHANGED,
EVENT_POSITION_DISCONTINUITY,
EVENT_REPEAT_MODE_CHANGED,
EVENT_SHUFFLE_MODE_ENABLED_CHANGED)) {
EVENT_SHUFFLE_MODE_ENABLED_CHANGED,
EVENT_MEDIA_METADATA_CHANGED)) {
postStartOrUpdateNotification();
}
}
......
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.ui;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.Player;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Tests for the {@link DefaultMediaDescriptionAdapter}. */
@RunWith(AndroidJUnit4.class)
public class DefaultMediaDescriptionAdapterTest {
@Test
public void getters_returnMediaMetadataValues() {
Context context = ApplicationProvider.getApplicationContext();
Player player = mock(Player.class);
MediaMetadata mediaMetadata =
new MediaMetadata.Builder().setDisplayTitle("display title").setArtist("artist").build();
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE);
DefaultMediaDescriptionAdapter adapter = new DefaultMediaDescriptionAdapter(pendingIntent);
when(player.getMediaMetadata()).thenReturn(mediaMetadata);
assertThat(adapter.createCurrentContentIntent(player)).isEqualTo(pendingIntent);
assertThat(adapter.getCurrentContentTitle(player).toString())
.isEqualTo(mediaMetadata.displayTitle.toString());
assertThat(adapter.getCurrentContentText(player).toString())
.isEqualTo(mediaMetadata.artist.toString());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment