mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Implement a DefaultMediaDescriptionAdapter that uses MediaMetadata.
PiperOrigin-RevId: 384681659
This commit is contained in:
parent
6512463280
commit
b9ac5a145f
4 changed files with 174 additions and 9 deletions
|
|
@ -37,6 +37,9 @@
|
||||||
These methods are all overrides and are already deprecated on `Player`
|
These methods are all overrides and are already deprecated on `Player`
|
||||||
and the respective `ExoPlayer` component classes (since 2.14.0).
|
and the respective `ExoPlayer` component classes (since 2.14.0).
|
||||||
* Rename `Player.EventFlags` IntDef to `Player.Event`.
|
* 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 deprecated symbols:
|
||||||
* Remove `Player.getPlaybackError`. Use `Player.getPlayerError` instead.
|
* Remove `Player.getPlaybackError`. Use `Player.getPlayerError` instead.
|
||||||
* Remove `Player.getCurrentTag`. Use `Player.getCurrentMediaItem` and
|
* Remove `Player.getCurrentTag`. Use `Player.getCurrentMediaItem` and
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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_NEXT_WINDOW;
|
||||||
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_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_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_PARAMETERS_CHANGED;
|
||||||
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED;
|
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED;
|
||||||
import static com.google.android.exoplayer2.Player.EVENT_PLAY_WHEN_READY_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 Context context;
|
||||||
private final int notificationId;
|
private final int notificationId;
|
||||||
private final String channelId;
|
private final String channelId;
|
||||||
private final MediaDescriptionAdapter mediaDescriptionAdapter;
|
|
||||||
|
|
||||||
@Nullable private NotificationListener notificationListener;
|
@Nullable private NotificationListener notificationListener;
|
||||||
@Nullable private CustomActionReceiver customActionReceiver;
|
@Nullable private CustomActionReceiver customActionReceiver;
|
||||||
|
private MediaDescriptionAdapter mediaDescriptionAdapter;
|
||||||
private int channelNameResourceId;
|
private int channelNameResourceId;
|
||||||
private int channelDescriptionResourceId;
|
private int channelDescriptionResourceId;
|
||||||
private int channelImportance;
|
private int channelImportance;
|
||||||
|
|
@ -325,24 +326,33 @@ public class PlayerNotificationManager {
|
||||||
@Nullable private String groupKey;
|
@Nullable private String groupKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance.
|
* @deprecated Use {@link #Builder(Context, int, String)} instead, then call {@link
|
||||||
*
|
* #setMediaDescriptionAdapter(MediaDescriptionAdapter)}.
|
||||||
* @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
|
||||||
public Builder(
|
public Builder(
|
||||||
Context context,
|
Context context,
|
||||||
int notificationId,
|
int notificationId,
|
||||||
String channelId,
|
String channelId,
|
||||||
MediaDescriptionAdapter mediaDescriptionAdapter) {
|
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);
|
checkArgument(notificationId > 0);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.notificationId = notificationId;
|
this.notificationId = notificationId;
|
||||||
this.channelId = channelId;
|
this.channelId = channelId;
|
||||||
this.mediaDescriptionAdapter = mediaDescriptionAdapter;
|
|
||||||
channelImportance = NotificationUtil.IMPORTANCE_LOW;
|
channelImportance = NotificationUtil.IMPORTANCE_LOW;
|
||||||
|
mediaDescriptionAdapter = new DefaultMediaDescriptionAdapter(/* pendingIntent= */ null);
|
||||||
smallIconResourceId = R.drawable.exo_notification_small_icon;
|
smallIconResourceId = R.drawable.exo_notification_small_icon;
|
||||||
playActionIconResourceId = R.drawable.exo_notification_play;
|
playActionIconResourceId = R.drawable.exo_notification_play;
|
||||||
pauseActionIconResourceId = R.drawable.exo_notification_pause;
|
pauseActionIconResourceId = R.drawable.exo_notification_pause;
|
||||||
|
|
@ -529,6 +539,18 @@ public class PlayerNotificationManager {
|
||||||
return this;
|
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}. */
|
/** Builds the {@link PlayerNotificationManager}. */
|
||||||
public PlayerNotificationManager build() {
|
public PlayerNotificationManager build() {
|
||||||
if (channelNameResourceId != 0) {
|
if (channelNameResourceId != 0) {
|
||||||
|
|
@ -539,6 +561,7 @@ public class PlayerNotificationManager {
|
||||||
channelDescriptionResourceId,
|
channelDescriptionResourceId,
|
||||||
channelImportance);
|
channelImportance);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PlayerNotificationManager(
|
return new PlayerNotificationManager(
|
||||||
context,
|
context,
|
||||||
channelId,
|
channelId,
|
||||||
|
|
@ -1487,7 +1510,8 @@ public class PlayerNotificationManager {
|
||||||
EVENT_PLAYBACK_PARAMETERS_CHANGED,
|
EVENT_PLAYBACK_PARAMETERS_CHANGED,
|
||||||
EVENT_POSITION_DISCONTINUITY,
|
EVENT_POSITION_DISCONTINUITY,
|
||||||
EVENT_REPEAT_MODE_CHANGED,
|
EVENT_REPEAT_MODE_CHANGED,
|
||||||
EVENT_SHUFFLE_MODE_ENABLED_CHANGED)) {
|
EVENT_SHUFFLE_MODE_ENABLED_CHANGED,
|
||||||
|
EVENT_MEDIA_METADATA_CHANGED)) {
|
||||||
postStartOrUpdateNotification();
|
postStartOrUpdateNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue