Commit e2ece2f5 by tonihei Committed by christosts

Add missing command checks in UI module

The commands are partly checked already before enabling
features or calling player methods, but the checks were
still missing in many places.

#minor-release

PiperOrigin-RevId: 504589888
parent e8ffc7b6
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package androidx.media3.ui; package androidx.media3.ui;
import static androidx.media3.common.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
...@@ -48,6 +50,9 @@ public final class DefaultMediaDescriptionAdapter implements MediaDescriptionAda ...@@ -48,6 +50,9 @@ public final class DefaultMediaDescriptionAdapter implements MediaDescriptionAda
@Override @Override
public CharSequence getCurrentContentTitle(Player player) { public CharSequence getCurrentContentTitle(Player player) {
if (!player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)) {
return "";
}
@Nullable CharSequence displayTitle = player.getMediaMetadata().displayTitle; @Nullable CharSequence displayTitle = player.getMediaMetadata().displayTitle;
if (!TextUtils.isEmpty(displayTitle)) { if (!TextUtils.isEmpty(displayTitle)) {
return displayTitle; return displayTitle;
...@@ -66,6 +71,9 @@ public final class DefaultMediaDescriptionAdapter implements MediaDescriptionAda ...@@ -66,6 +71,9 @@ public final class DefaultMediaDescriptionAdapter implements MediaDescriptionAda
@Nullable @Nullable
@Override @Override
public CharSequence getCurrentContentText(Player player) { public CharSequence getCurrentContentText(Player player) {
if (!player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)) {
return null;
}
@Nullable CharSequence artist = player.getMediaMetadata().artist; @Nullable CharSequence artist = player.getMediaMetadata().artist;
if (!TextUtils.isEmpty(artist)) { if (!TextUtils.isEmpty(artist)) {
return artist; return artist;
...@@ -77,6 +85,9 @@ public final class DefaultMediaDescriptionAdapter implements MediaDescriptionAda ...@@ -77,6 +85,9 @@ public final class DefaultMediaDescriptionAdapter implements MediaDescriptionAda
@Nullable @Nullable
@Override @Override
public Bitmap getCurrentLargeIcon(Player player, BitmapCallback callback) { public Bitmap getCurrentLargeIcon(Player player, BitmapCallback callback) {
if (!player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)) {
return null;
}
@Nullable byte[] data = player.getMediaMetadata().artworkData; @Nullable byte[] data = player.getMediaMetadata().artworkData;
if (data == null) { if (data == null) {
return null; return null;
......
...@@ -15,11 +15,22 @@ ...@@ -15,11 +15,22 @@
*/ */
package androidx.media3.ui; package androidx.media3.ui;
import static androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_GET_TIMELINE;
import static androidx.media3.common.Player.COMMAND_GET_TRACKS;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
import static androidx.media3.common.Player.COMMAND_PREPARE;
import static androidx.media3.common.Player.COMMAND_SEEK_BACK; import static androidx.media3.common.Player.COMMAND_SEEK_BACK;
import static androidx.media3.common.Player.COMMAND_SEEK_FORWARD; import static androidx.media3.common.Player.COMMAND_SEEK_FORWARD;
import static androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_DEFAULT_POSITION;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT; import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS;
import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE;
import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE;
import static androidx.media3.common.Player.COMMAND_SET_SPEED_AND_PITCH;
import static androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS;
import static androidx.media3.common.Player.EVENT_AVAILABLE_COMMANDS_CHANGED; import static androidx.media3.common.Player.EVENT_AVAILABLE_COMMANDS_CHANGED;
import static androidx.media3.common.Player.EVENT_IS_PLAYING_CHANGED; import static androidx.media3.common.Player.EVENT_IS_PLAYING_CHANGED;
import static androidx.media3.common.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED; import static androidx.media3.common.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED;
...@@ -35,6 +46,7 @@ import static androidx.media3.common.Player.EVENT_TRACKS_CHANGED; ...@@ -35,6 +46,7 @@ import static androidx.media3.common.Player.EVENT_TRACKS_CHANGED;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
import static androidx.media3.common.util.Util.getDrawable; import static androidx.media3.common.util.Util.getDrawable;
import static androidx.media3.common.util.Util.msToUs;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
...@@ -798,7 +810,7 @@ public class PlayerControlView extends FrameLayout { ...@@ -798,7 +810,7 @@ public class PlayerControlView extends FrameLayout {
*/ */
public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) {
this.repeatToggleModes = repeatToggleModes; this.repeatToggleModes = repeatToggleModes;
if (player != null) { if (player != null && player.isCommandAvailable(COMMAND_SET_REPEAT_MODE)) {
@Player.RepeatMode int currentMode = player.getRepeatMode(); @Player.RepeatMode int currentMode = player.getRepeatMode();
if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE
&& currentMode != Player.REPEAT_MODE_OFF) { && currentMode != Player.REPEAT_MODE_OFF) {
...@@ -1062,7 +1074,7 @@ public class PlayerControlView extends FrameLayout { ...@@ -1062,7 +1074,7 @@ public class PlayerControlView extends FrameLayout {
} }
@Nullable Player player = this.player; @Nullable Player player = this.player;
if (player == null) { if (player == null || !player.isCommandAvailable(COMMAND_SET_REPEAT_MODE)) {
updateButton(/* enabled= */ false, repeatToggleButton); updateButton(/* enabled= */ false, repeatToggleButton);
repeatToggleButton.setImageDrawable(repeatOffButtonDrawable); repeatToggleButton.setImageDrawable(repeatOffButtonDrawable);
repeatToggleButton.setContentDescription(repeatOffButtonContentDescription); repeatToggleButton.setContentDescription(repeatOffButtonContentDescription);
...@@ -1096,7 +1108,7 @@ public class PlayerControlView extends FrameLayout { ...@@ -1096,7 +1108,7 @@ public class PlayerControlView extends FrameLayout {
@Nullable Player player = this.player; @Nullable Player player = this.player;
if (!controlViewLayoutManager.getShowButton(shuffleButton)) { if (!controlViewLayoutManager.getShowButton(shuffleButton)) {
updateButton(/* enabled= */ false, shuffleButton); updateButton(/* enabled= */ false, shuffleButton);
} else if (player == null) { } else if (player == null || !player.isCommandAvailable(COMMAND_SET_SHUFFLE_MODE)) {
updateButton(/* enabled= */ false, shuffleButton); updateButton(/* enabled= */ false, shuffleButton);
shuffleButton.setImageDrawable(shuffleOffButtonDrawable); shuffleButton.setImageDrawable(shuffleOffButtonDrawable);
shuffleButton.setContentDescription(shuffleOffContentDescription); shuffleButton.setContentDescription(shuffleOffContentDescription);
...@@ -1120,8 +1132,8 @@ public class PlayerControlView extends FrameLayout { ...@@ -1120,8 +1132,8 @@ public class PlayerControlView extends FrameLayout {
textTrackSelectionAdapter.clear(); textTrackSelectionAdapter.clear();
audioTrackSelectionAdapter.clear(); audioTrackSelectionAdapter.clear();
if (player == null if (player == null
|| !player.isCommandAvailable(Player.COMMAND_GET_TRACKS) || !player.isCommandAvailable(COMMAND_GET_TRACKS)
|| !player.isCommandAvailable(Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS)) { || !player.isCommandAvailable(COMMAND_SET_TRACK_SELECTION_PARAMETERS)) {
return; return;
} }
Tracks tracks = player.getCurrentTracks(); Tracks tracks = player.getCurrentTracks();
...@@ -1162,12 +1174,14 @@ public class PlayerControlView extends FrameLayout { ...@@ -1162,12 +1174,14 @@ public class PlayerControlView extends FrameLayout {
if (player == null) { if (player == null) {
return; return;
} }
multiWindowTimeBar = multiWindowTimeBar = showMultiWindowTimeBar && canShowMultiWindowTimeBar(player, window);
showMultiWindowTimeBar && canShowMultiWindowTimeBar(player.getCurrentTimeline(), window);
currentWindowOffset = 0; currentWindowOffset = 0;
long durationUs = 0; long durationUs = 0;
int adGroupCount = 0; int adGroupCount = 0;
Timeline timeline = player.getCurrentTimeline(); Timeline timeline =
player.isCommandAvailable(COMMAND_GET_TIMELINE)
? player.getCurrentTimeline()
: Timeline.EMPTY;
if (!timeline.isEmpty()) { if (!timeline.isEmpty()) {
int currentWindowIndex = player.getCurrentMediaItemIndex(); int currentWindowIndex = player.getCurrentMediaItemIndex();
int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex; int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex;
...@@ -1209,6 +1223,11 @@ public class PlayerControlView extends FrameLayout { ...@@ -1209,6 +1223,11 @@ public class PlayerControlView extends FrameLayout {
} }
durationUs += window.durationUs; durationUs += window.durationUs;
} }
} else if (player.isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)) {
long playerDurationMs = player.getContentDuration();
if (playerDurationMs != C.TIME_UNSET) {
durationUs = msToUs(playerDurationMs);
}
} }
long durationMs = Util.usToMs(durationUs); long durationMs = Util.usToMs(durationUs);
if (durationView != null) { if (durationView != null) {
...@@ -1236,7 +1255,7 @@ public class PlayerControlView extends FrameLayout { ...@@ -1236,7 +1255,7 @@ public class PlayerControlView extends FrameLayout {
@Nullable Player player = this.player; @Nullable Player player = this.player;
long position = 0; long position = 0;
long bufferedPosition = 0; long bufferedPosition = 0;
if (player != null) { if (player != null && player.isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)) {
position = currentWindowOffset + player.getContentPosition(); position = currentWindowOffset + player.getContentPosition();
bufferedPosition = currentWindowOffset + player.getContentBufferedPosition(); bufferedPosition = currentWindowOffset + player.getContentBufferedPosition();
} }
...@@ -1314,7 +1333,7 @@ public class PlayerControlView extends FrameLayout { ...@@ -1314,7 +1333,7 @@ public class PlayerControlView extends FrameLayout {
} }
private void setPlaybackSpeed(float speed) { private void setPlaybackSpeed(float speed) {
if (player == null) { if (player == null || !player.isCommandAvailable(COMMAND_SET_SPEED_AND_PITCH)) {
return; return;
} }
player.setPlaybackParameters(player.getPlaybackParameters().withSpeed(speed)); player.setPlaybackParameters(player.getPlaybackParameters().withSpeed(speed));
...@@ -1335,11 +1354,12 @@ public class PlayerControlView extends FrameLayout { ...@@ -1335,11 +1354,12 @@ public class PlayerControlView extends FrameLayout {
} }
private void seekToTimeBarPosition(Player player, long positionMs) { private void seekToTimeBarPosition(Player player, long positionMs) {
int windowIndex; if (multiWindowTimeBar
Timeline timeline = player.getCurrentTimeline(); && player.isCommandAvailable(COMMAND_GET_TIMELINE)
if (multiWindowTimeBar && !timeline.isEmpty()) { && player.isCommandAvailable(COMMAND_SEEK_TO_MEDIA_ITEM)) {
Timeline timeline = player.getCurrentTimeline();
int windowCount = timeline.getWindowCount(); int windowCount = timeline.getWindowCount();
windowIndex = 0; int windowIndex = 0;
while (true) { while (true) {
long windowDurationMs = timeline.getWindow(windowIndex, window).getDurationMs(); long windowDurationMs = timeline.getWindow(windowIndex, window).getDurationMs();
if (positionMs < windowDurationMs) { if (positionMs < windowDurationMs) {
...@@ -1352,17 +1372,13 @@ public class PlayerControlView extends FrameLayout { ...@@ -1352,17 +1372,13 @@ public class PlayerControlView extends FrameLayout {
positionMs -= windowDurationMs; positionMs -= windowDurationMs;
windowIndex++; windowIndex++;
} }
} else { player.seekTo(windowIndex, positionMs);
windowIndex = player.getCurrentMediaItemIndex(); } else if (player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)) {
player.seekTo(positionMs);
} }
seekTo(player, windowIndex, positionMs);
updateProgress(); updateProgress();
} }
private void seekTo(Player player, int windowIndex, long positionMs) {
player.seekTo(windowIndex, positionMs);
}
private void onFullScreenButtonClicked(View v) { private void onFullScreenButtonClicked(View v) {
if (onFullScreenModeChangedListener == null) { if (onFullScreenModeChangedListener == null) {
return; return;
...@@ -1440,10 +1456,12 @@ public class PlayerControlView extends FrameLayout { ...@@ -1440,10 +1456,12 @@ public class PlayerControlView extends FrameLayout {
} }
if (event.getAction() == KeyEvent.ACTION_DOWN) { if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) { if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
if (player.getPlaybackState() != Player.STATE_ENDED) { if (player.getPlaybackState() != Player.STATE_ENDED
&& player.isCommandAvailable(COMMAND_SEEK_FORWARD)) {
player.seekForward(); player.seekForward();
} }
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) { } else if (keyCode == KeyEvent.KEYCODE_MEDIA_REWIND
&& player.isCommandAvailable(COMMAND_SEEK_BACK)) {
player.seekBack(); player.seekBack();
} else if (event.getRepeatCount() == 0) { } else if (event.getRepeatCount() == 0) {
switch (keyCode) { switch (keyCode) {
...@@ -1458,10 +1476,14 @@ public class PlayerControlView extends FrameLayout { ...@@ -1458,10 +1476,14 @@ public class PlayerControlView extends FrameLayout {
dispatchPause(player); dispatchPause(player);
break; break;
case KeyEvent.KEYCODE_MEDIA_NEXT: case KeyEvent.KEYCODE_MEDIA_NEXT:
player.seekToNext(); if (player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)) {
player.seekToNext();
}
break; break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
player.seekToPrevious(); if (player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS)) {
player.seekToPrevious();
}
break; break;
default: default:
break; break;
...@@ -1501,7 +1523,10 @@ public class PlayerControlView extends FrameLayout { ...@@ -1501,7 +1523,10 @@ public class PlayerControlView extends FrameLayout {
} }
private boolean shouldEnablePlayPauseButton() { private boolean shouldEnablePlayPauseButton() {
return player != null && !player.getCurrentTimeline().isEmpty(); return player != null
&& player.isCommandAvailable(COMMAND_PLAY_PAUSE)
&& (!player.isCommandAvailable(COMMAND_GET_TIMELINE)
|| !player.getCurrentTimeline().isEmpty());
} }
private boolean shouldShowPauseButton() { private boolean shouldShowPauseButton() {
...@@ -1522,16 +1547,21 @@ public class PlayerControlView extends FrameLayout { ...@@ -1522,16 +1547,21 @@ public class PlayerControlView extends FrameLayout {
private void dispatchPlay(Player player) { private void dispatchPlay(Player player) {
@State int state = player.getPlaybackState(); @State int state = player.getPlaybackState();
if (state == Player.STATE_IDLE) { if (state == Player.STATE_IDLE && player.isCommandAvailable(COMMAND_PREPARE)) {
player.prepare(); player.prepare();
} else if (state == Player.STATE_ENDED) { } else if (state == Player.STATE_ENDED
seekTo(player, player.getCurrentMediaItemIndex(), C.TIME_UNSET); && player.isCommandAvailable(COMMAND_SEEK_TO_DEFAULT_POSITION)) {
player.seekToDefaultPosition();
}
if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.play();
} }
player.play();
} }
private void dispatchPause(Player player) { private void dispatchPause(Player player) {
player.pause(); if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.pause();
}
} }
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
...@@ -1547,13 +1577,18 @@ public class PlayerControlView extends FrameLayout { ...@@ -1547,13 +1577,18 @@ public class PlayerControlView extends FrameLayout {
} }
/** /**
* Returns whether the specified {@code timeline} can be shown on a multi-window time bar. * Returns whether the specified {@code player} can be shown on a multi-window time bar.
* *
* @param timeline The {@link Timeline} to check. * @param player The {@link Player} to check.
* @param window A scratch {@link Timeline.Window} instance. * @param window A scratch {@link Timeline.Window} instance.
* @return Whether the specified timeline can be shown on a multi-window time bar. * @return Whether the specified timeline can be shown on a multi-window time bar.
*/ */
private static boolean canShowMultiWindowTimeBar(Timeline timeline, Timeline.Window window) { private static boolean canShowMultiWindowTimeBar(Player player, Timeline.Window window) {
if (!player.isCommandAvailable(COMMAND_GET_TIMELINE)
|| !player.isCommandAvailable(COMMAND_SEEK_TO_MEDIA_ITEM)) {
return false;
}
Timeline timeline = player.getCurrentTimeline();
if (timeline.getWindowCount() > MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR) { if (timeline.getWindowCount() > MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR) {
return false; return false;
} }
...@@ -1674,22 +1709,33 @@ public class PlayerControlView extends FrameLayout { ...@@ -1674,22 +1709,33 @@ public class PlayerControlView extends FrameLayout {
} }
controlViewLayoutManager.resetHideCallbacks(); controlViewLayoutManager.resetHideCallbacks();
if (nextButton == view) { if (nextButton == view) {
player.seekToNext(); if (player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)) {
player.seekToNext();
}
} else if (previousButton == view) { } else if (previousButton == view) {
player.seekToPrevious(); if (player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS)) {
player.seekToPrevious();
}
} else if (fastForwardButton == view) { } else if (fastForwardButton == view) {
if (player.getPlaybackState() != Player.STATE_ENDED) { if (player.getPlaybackState() != Player.STATE_ENDED
&& player.isCommandAvailable(COMMAND_SEEK_FORWARD)) {
player.seekForward(); player.seekForward();
} }
} else if (rewindButton == view) { } else if (rewindButton == view) {
player.seekBack(); if (player.isCommandAvailable(COMMAND_SEEK_BACK)) {
player.seekBack();
}
} else if (playPauseButton == view) { } else if (playPauseButton == view) {
dispatchPlayPause(player); dispatchPlayPause(player);
} else if (repeatToggleButton == view) { } else if (repeatToggleButton == view) {
player.setRepeatMode( if (player.isCommandAvailable(COMMAND_SET_REPEAT_MODE)) {
RepeatModeUtil.getNextRepeatMode(player.getRepeatMode(), repeatToggleModes)); player.setRepeatMode(
RepeatModeUtil.getNextRepeatMode(player.getRepeatMode(), repeatToggleModes));
}
} else if (shuffleButton == view) { } else if (shuffleButton == view) {
player.setShuffleModeEnabled(!player.getShuffleModeEnabled()); if (player.isCommandAvailable(COMMAND_SET_SHUFFLE_MODE)) {
player.setShuffleModeEnabled(!player.getShuffleModeEnabled());
}
} else if (settingsButton == view) { } else if (settingsButton == view) {
controlViewLayoutManager.removeHideCallbacks(); controlViewLayoutManager.removeHideCallbacks();
displaySettingsWindow(settingsAdapter, settingsButton); displaySettingsWindow(settingsAdapter, settingsButton);
...@@ -1892,7 +1938,8 @@ public class PlayerControlView extends FrameLayout { ...@@ -1892,7 +1938,8 @@ public class PlayerControlView extends FrameLayout {
holder.checkView.setVisibility(isTrackSelectionOff ? VISIBLE : INVISIBLE); holder.checkView.setVisibility(isTrackSelectionOff ? VISIBLE : INVISIBLE);
holder.itemView.setOnClickListener( holder.itemView.setOnClickListener(
v -> { v -> {
if (player != null) { if (player != null
&& player.isCommandAvailable(COMMAND_SET_TRACK_SELECTION_PARAMETERS)) {
TrackSelectionParameters trackSelectionParameters = TrackSelectionParameters trackSelectionParameters =
player.getTrackSelectionParameters(); player.getTrackSelectionParameters();
player.setTrackSelectionParameters( player.setTrackSelectionParameters(
...@@ -1933,7 +1980,8 @@ public class PlayerControlView extends FrameLayout { ...@@ -1933,7 +1980,8 @@ public class PlayerControlView extends FrameLayout {
holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE); holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE);
holder.itemView.setOnClickListener( holder.itemView.setOnClickListener(
v -> { v -> {
if (player == null) { if (player == null
|| !player.isCommandAvailable(COMMAND_SET_TRACK_SELECTION_PARAMETERS)) {
return; return;
} }
TrackSelectionParameters trackSelectionParameters = TrackSelectionParameters trackSelectionParameters =
...@@ -2036,6 +2084,9 @@ public class PlayerControlView extends FrameLayout { ...@@ -2036,6 +2084,9 @@ public class PlayerControlView extends FrameLayout {
holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE); holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE);
holder.itemView.setOnClickListener( holder.itemView.setOnClickListener(
v -> { v -> {
if (!player.isCommandAvailable(COMMAND_SET_TRACK_SELECTION_PARAMETERS)) {
return;
}
TrackSelectionParameters trackSelectionParameters = TrackSelectionParameters trackSelectionParameters =
player.getTrackSelectionParameters(); player.getTrackSelectionParameters();
player.setTrackSelectionParameters( player.setTrackSelectionParameters(
......
...@@ -15,10 +15,17 @@ ...@@ -15,10 +15,17 @@
*/ */
package androidx.media3.ui; package androidx.media3.ui;
import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS;
import static androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_GET_TIMELINE;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
import static androidx.media3.common.Player.COMMAND_PREPARE;
import static androidx.media3.common.Player.COMMAND_SEEK_BACK; import static androidx.media3.common.Player.COMMAND_SEEK_BACK;
import static androidx.media3.common.Player.COMMAND_SEEK_FORWARD; import static androidx.media3.common.Player.COMMAND_SEEK_FORWARD;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_DEFAULT_POSITION;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT; import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS;
import static androidx.media3.common.Player.COMMAND_STOP;
import static androidx.media3.common.Player.EVENT_IS_PLAYING_CHANGED; import static androidx.media3.common.Player.EVENT_IS_PLAYING_CHANGED;
import static androidx.media3.common.Player.EVENT_MEDIA_METADATA_CHANGED; import static androidx.media3.common.Player.EVENT_MEDIA_METADATA_CHANGED;
import static androidx.media3.common.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED; import static androidx.media3.common.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED;
...@@ -1205,7 +1212,9 @@ public class PlayerNotificationManager { ...@@ -1205,7 +1212,9 @@ public class PlayerNotificationManager {
@Nullable NotificationCompat.Builder builder, @Nullable NotificationCompat.Builder builder,
boolean ongoing, boolean ongoing,
@Nullable Bitmap largeIcon) { @Nullable Bitmap largeIcon) {
if (player.getPlaybackState() == Player.STATE_IDLE && player.getCurrentTimeline().isEmpty()) { if (player.getPlaybackState() == Player.STATE_IDLE
&& player.isCommandAvailable(COMMAND_GET_TIMELINE)
&& player.getCurrentTimeline().isEmpty()) {
builderActions = null; builderActions = null;
return null; return null;
} }
...@@ -1259,6 +1268,7 @@ public class PlayerNotificationManager { ...@@ -1259,6 +1268,7 @@ public class PlayerNotificationManager {
// Changing "showWhen" causes notification flicker if SDK_INT < 21. // Changing "showWhen" causes notification flicker if SDK_INT < 21.
if (Util.SDK_INT >= 21 if (Util.SDK_INT >= 21
&& useChronometer && useChronometer
&& player.isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)
&& player.isPlaying() && player.isPlaying()
&& !player.isPlayingAd() && !player.isPlayingAd()
&& !player.isCurrentMediaItemDynamic() && !player.isCurrentMediaItemDynamic()
...@@ -1537,24 +1547,43 @@ public class PlayerNotificationManager { ...@@ -1537,24 +1547,43 @@ public class PlayerNotificationManager {
} }
String action = intent.getAction(); String action = intent.getAction();
if (ACTION_PLAY.equals(action)) { if (ACTION_PLAY.equals(action)) {
if (player.getPlaybackState() == Player.STATE_IDLE) { if (player.getPlaybackState() == Player.STATE_IDLE
&& player.isCommandAvailable(COMMAND_PREPARE)) {
player.prepare(); player.prepare();
} else if (player.getPlaybackState() == Player.STATE_ENDED) { } else if (player.getPlaybackState() == Player.STATE_ENDED
player.seekToDefaultPosition(player.getCurrentMediaItemIndex()); && player.isCommandAvailable(COMMAND_SEEK_TO_DEFAULT_POSITION)) {
player.seekToDefaultPosition();
}
if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.play();
} }
player.play();
} else if (ACTION_PAUSE.equals(action)) { } else if (ACTION_PAUSE.equals(action)) {
player.pause(); if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.pause();
}
} else if (ACTION_PREVIOUS.equals(action)) { } else if (ACTION_PREVIOUS.equals(action)) {
player.seekToPrevious(); if (player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS)) {
player.seekToPrevious();
}
} else if (ACTION_REWIND.equals(action)) { } else if (ACTION_REWIND.equals(action)) {
player.seekBack(); if (player.isCommandAvailable(COMMAND_SEEK_BACK)) {
player.seekBack();
}
} else if (ACTION_FAST_FORWARD.equals(action)) { } else if (ACTION_FAST_FORWARD.equals(action)) {
player.seekForward(); if (player.isCommandAvailable(COMMAND_SEEK_FORWARD)) {
player.seekForward();
}
} else if (ACTION_NEXT.equals(action)) { } else if (ACTION_NEXT.equals(action)) {
player.seekToNext(); if (player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)) {
player.seekToNext();
}
} else if (ACTION_STOP.equals(action)) { } else if (ACTION_STOP.equals(action)) {
player.stop(/* reset= */ true); if (player.isCommandAvailable(COMMAND_STOP)) {
player.stop();
}
if (player.isCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)) {
player.clearMediaItems();
}
} else if (ACTION_DISMISS.equals(action)) { } else if (ACTION_DISMISS.equals(action)) {
stopNotification(/* dismissedByUser= */ true); stopNotification(/* dismissedByUser= */ true);
} else if (action != null } else if (action != null
......
...@@ -15,7 +15,11 @@ ...@@ -15,7 +15,11 @@
*/ */
package androidx.media3.ui; package androidx.media3.ui;
import static androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
import static androidx.media3.common.Player.COMMAND_GET_TEXT; import static androidx.media3.common.Player.COMMAND_GET_TEXT;
import static androidx.media3.common.Player.COMMAND_GET_TIMELINE;
import static androidx.media3.common.Player.COMMAND_GET_TRACKS;
import static androidx.media3.common.Player.COMMAND_SET_VIDEO_SURFACE; import static androidx.media3.common.Player.COMMAND_SET_VIDEO_SURFACE;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.getDrawable; import static androidx.media3.common.util.Util.getDrawable;
...@@ -527,10 +531,12 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -527,10 +531,12 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
@Nullable Player oldPlayer = this.player; @Nullable Player oldPlayer = this.player;
if (oldPlayer != null) { if (oldPlayer != null) {
oldPlayer.removeListener(componentListener); oldPlayer.removeListener(componentListener);
if (surfaceView instanceof TextureView) { if (oldPlayer.isCommandAvailable(COMMAND_SET_VIDEO_SURFACE)) {
oldPlayer.clearVideoTextureView((TextureView) surfaceView); if (surfaceView instanceof TextureView) {
} else if (surfaceView instanceof SurfaceView) { oldPlayer.clearVideoTextureView((TextureView) surfaceView);
oldPlayer.clearVideoSurfaceView((SurfaceView) surfaceView); } else if (surfaceView instanceof SurfaceView) {
oldPlayer.clearVideoSurfaceView((SurfaceView) surfaceView);
}
} }
} }
if (subtitleView != null) { if (subtitleView != null) {
...@@ -743,7 +749,9 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -743,7 +749,9 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
if (player != null && player.isPlayingAd()) { if (player != null
&& player.isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)
&& player.isPlayingAd()) {
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
...@@ -1274,7 +1282,8 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1274,7 +1282,8 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
} }
int playbackState = player.getPlaybackState(); int playbackState = player.getPlaybackState();
return controllerAutoShow return controllerAutoShow
&& !player.getCurrentTimeline().isEmpty() && (!player.isCommandAvailable(COMMAND_GET_TIMELINE)
|| !player.getCurrentTimeline().isEmpty())
&& (playbackState == Player.STATE_IDLE && (playbackState == Player.STATE_IDLE
|| playbackState == Player.STATE_ENDED || playbackState == Player.STATE_ENDED
|| !checkNotNull(player).getPlayWhenReady()); || !checkNotNull(player).getPlayWhenReady());
...@@ -1289,12 +1298,17 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1289,12 +1298,17 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
} }
private boolean isPlayingAd() { private boolean isPlayingAd() {
return player != null && player.isPlayingAd() && player.getPlayWhenReady(); return player != null
&& player.isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)
&& player.isPlayingAd()
&& player.getPlayWhenReady();
} }
private void updateForCurrentTrackSelections(boolean isNewPlayer) { private void updateForCurrentTrackSelections(boolean isNewPlayer) {
@Nullable Player player = this.player; @Nullable Player player = this.player;
if (player == null || player.getCurrentTracks().isEmpty()) { if (player == null
|| !player.isCommandAvailable(COMMAND_GET_TRACKS)
|| player.getCurrentTracks().isEmpty()) {
if (!keepContentOnPlayerReset) { if (!keepContentOnPlayerReset) {
hideArtwork(); hideArtwork();
closeShutter(); closeShutter();
...@@ -1318,7 +1332,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1318,7 +1332,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
closeShutter(); closeShutter();
// Display artwork if enabled and available, else hide it. // Display artwork if enabled and available, else hide it.
if (useArtwork()) { if (useArtwork()) {
if (setArtworkFromMediaMetadata(player.getMediaMetadata())) { if (setArtworkFromMediaMetadata(player)) {
return; return;
} }
if (setDrawableArtwork(defaultArtwork)) { if (setDrawableArtwork(defaultArtwork)) {
...@@ -1330,7 +1344,11 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1330,7 +1344,11 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
} }
@RequiresNonNull("artworkView") @RequiresNonNull("artworkView")
private boolean setArtworkFromMediaMetadata(MediaMetadata mediaMetadata) { private boolean setArtworkFromMediaMetadata(Player player) {
if (!player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)) {
return false;
}
MediaMetadata mediaMetadata = player.getMediaMetadata();
if (mediaMetadata.artworkData == null) { if (mediaMetadata.artworkData == null) {
return false; return false;
} }
...@@ -1549,10 +1567,14 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1549,10 +1567,14 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
// is necessary to avoid closing the shutter when such a transition occurs. See: // is necessary to avoid closing the shutter when such a transition occurs. See:
// https://github.com/google/ExoPlayer/issues/5507. // https://github.com/google/ExoPlayer/issues/5507.
Player player = checkNotNull(PlayerView.this.player); Player player = checkNotNull(PlayerView.this.player);
Timeline timeline = player.getCurrentTimeline(); Timeline timeline =
player.isCommandAvailable(COMMAND_GET_TIMELINE)
? player.getCurrentTimeline()
: Timeline.EMPTY;
if (timeline.isEmpty()) { if (timeline.isEmpty()) {
lastPeriodUidWithTracks = null; lastPeriodUidWithTracks = null;
} else if (!player.getCurrentTracks().isEmpty()) { } else if (player.isCommandAvailable(COMMAND_GET_TRACKS)
&& !player.getCurrentTracks().isEmpty()) {
lastPeriodUidWithTracks = lastPeriodUidWithTracks =
timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid; timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid;
} else if (lastPeriodUidWithTracks != null) { } else if (lastPeriodUidWithTracks != null) {
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
*/ */
package androidx.media3.ui; package androidx.media3.ui;
import static androidx.media3.common.Player.COMMAND_GET_TRACKS;
import static androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
...@@ -102,7 +105,9 @@ public final class TrackSelectionDialogBuilder { ...@@ -102,7 +105,9 @@ public final class TrackSelectionDialogBuilder {
Context context, CharSequence title, Player player, @C.TrackType int trackType) { Context context, CharSequence title, Player player, @C.TrackType int trackType) {
this.context = context; this.context = context;
this.title = title; this.title = title;
List<Tracks.Group> allTrackGroups = player.getCurrentTracks().getGroups(); Tracks tracks =
player.isCommandAvailable(COMMAND_GET_TRACKS) ? player.getCurrentTracks() : Tracks.EMPTY;
List<Tracks.Group> allTrackGroups = tracks.getGroups();
trackGroups = new ArrayList<>(); trackGroups = new ArrayList<>();
for (int i = 0; i < allTrackGroups.size(); i++) { for (int i = 0; i < allTrackGroups.size(); i++) {
Tracks.Group trackGroup = allTrackGroups.get(i); Tracks.Group trackGroup = allTrackGroups.get(i);
...@@ -113,6 +118,9 @@ public final class TrackSelectionDialogBuilder { ...@@ -113,6 +118,9 @@ public final class TrackSelectionDialogBuilder {
overrides = player.getTrackSelectionParameters().overrides; overrides = player.getTrackSelectionParameters().overrides;
callback = callback =
(isDisabled, overrides) -> { (isDisabled, overrides) -> {
if (!player.isCommandAvailable(COMMAND_SET_TRACK_SELECTION_PARAMETERS)) {
return;
}
TrackSelectionParameters.Builder parametersBuilder = TrackSelectionParameters.Builder parametersBuilder =
player.getTrackSelectionParameters().buildUpon(); player.getTrackSelectionParameters().buildUpon();
parametersBuilder.setTrackTypeDisabled(trackType, isDisabled); parametersBuilder.setTrackTypeDisabled(trackType, isDisabled);
......
...@@ -34,7 +34,7 @@ import org.junit.runner.RunWith; ...@@ -34,7 +34,7 @@ import org.junit.runner.RunWith;
public class DefaultMediaDescriptionAdapterTest { public class DefaultMediaDescriptionAdapterTest {
@Test @Test
public void getters_returnMediaMetadataValues() { public void getters_withGetMetatadataCommandAvailable_returnMediaMetadataValues() {
Context context = ApplicationProvider.getApplicationContext(); Context context = ApplicationProvider.getApplicationContext();
Player player = mock(Player.class); Player player = mock(Player.class);
MediaMetadata mediaMetadata = MediaMetadata mediaMetadata =
...@@ -43,6 +43,7 @@ public class DefaultMediaDescriptionAdapterTest { ...@@ -43,6 +43,7 @@ public class DefaultMediaDescriptionAdapterTest {
PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE); PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE);
DefaultMediaDescriptionAdapter adapter = new DefaultMediaDescriptionAdapter(pendingIntent); DefaultMediaDescriptionAdapter adapter = new DefaultMediaDescriptionAdapter(pendingIntent);
when(player.isCommandAvailable(Player.COMMAND_GET_MEDIA_ITEMS_METADATA)).thenReturn(true);
when(player.getMediaMetadata()).thenReturn(mediaMetadata); when(player.getMediaMetadata()).thenReturn(mediaMetadata);
assertThat(adapter.createCurrentContentIntent(player)).isEqualTo(pendingIntent); assertThat(adapter.createCurrentContentIntent(player)).isEqualTo(pendingIntent);
...@@ -51,4 +52,22 @@ public class DefaultMediaDescriptionAdapterTest { ...@@ -51,4 +52,22 @@ public class DefaultMediaDescriptionAdapterTest {
assertThat(adapter.getCurrentContentText(player).toString()) assertThat(adapter.getCurrentContentText(player).toString())
.isEqualTo(mediaMetadata.artist.toString()); .isEqualTo(mediaMetadata.artist.toString());
} }
@Test
public void getters_withoutGetMetatadataCommandAvailable_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.isCommandAvailable(Player.COMMAND_GET_MEDIA_ITEMS_METADATA)).thenReturn(false);
when(player.getMediaMetadata()).thenReturn(mediaMetadata);
assertThat(adapter.createCurrentContentIntent(player)).isEqualTo(pendingIntent);
assertThat(adapter.getCurrentContentTitle(player).toString()).isEqualTo("");
assertThat(adapter.getCurrentContentText(player)).isNull();
}
} }
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