From 9d2d3340917dd6f8bc4a19c481570e6dbaf31bb6 Mon Sep 17 00:00:00 2001 From: kimvde Date: Thu, 11 Mar 2021 15:57:17 +0000 Subject: [PATCH] Add available commands to prepare/play/pause/stop/release. PiperOrigin-RevId: 362292208 --- .../exoplayer2/ext/cast/CastPlayer.java | 3 +- .../exoplayer2/ext/cast/CastPlayerTest.java | 18 ++++++++-- .../google/android/exoplayer2/BasePlayer.java | 4 +++ .../com/google/android/exoplayer2/Player.java | 35 ++++++++++++++----- .../android/exoplayer2/util/ExoFlags.java | 14 ++++++++ .../android/exoplayer2/ExoPlayerImpl.java | 2 +- .../android/exoplayer2/ExoPlayerTest.java | 20 +++++++++-- 7 files changed, 79 insertions(+), 17 deletions(-) diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java index 81e9a80c98..2e0a2f59b9 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java @@ -140,14 +140,13 @@ public final class CastPlayer extends BasePlayer { Looper.getMainLooper(), Clock.DEFAULT, (listener, flags) -> listener.onEvents(/* player= */ this, new Events(flags))); - playWhenReady = new StateHolder<>(false); repeatMode = new StateHolder<>(REPEAT_MODE_OFF); playbackState = STATE_IDLE; currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE; currentTrackGroups = TrackGroupArray.EMPTY; currentTrackSelection = EMPTY_TRACK_SELECTION_ARRAY; - availableCommands = Commands.EMPTY; + availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build(); pendingSeekWindowIndex = C.INDEX_UNSET; pendingSeekPositionMs = C.TIME_UNSET; diff --git a/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/CastPlayerTest.java b/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/CastPlayerTest.java index f9ac6a541c..153c6b88c1 100644 --- a/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/CastPlayerTest.java +++ b/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/CastPlayerTest.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.ext.cast; +import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE; +import static com.google.android.exoplayer2.Player.COMMAND_PREPARE_STOP_RELEASE; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static com.google.common.truth.Truth.assertThat; @@ -592,6 +594,12 @@ public class CastPlayerTest { assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse(); } + @Test + public void isCommandAvailable_containsPermanentCommands() { + assertThat(castPlayer.isCommandAvailable(COMMAND_PLAY_PAUSE)).isTrue(); + assertThat(castPlayer.isCommandAvailable(COMMAND_PREPARE_STOP_RELEASE)).isTrue(); + } + @Test public void seekTo_nextWindow_notifiesAvailableCommandsChanged() { when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null))) @@ -728,6 +736,7 @@ public class CastPlayerTest { @Test public void removeMediaItem_atTheEnd_notifiesAvailableCommandsChanged() { Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); + Player.Commands commandsWithoutSeek = createCommands(); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3); @@ -752,7 +761,7 @@ public class CastPlayerTest { ImmutableList.of(mediaItem1), /* mediaQueueItemIds= */ new int[] {1}, /* currentItemId= */ 1); - verify(mockListener).onAvailableCommandsChanged(Player.Commands.EMPTY); + verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); castPlayer.removeMediaItem(/* index= */ 0); @@ -769,6 +778,7 @@ public class CastPlayerTest { .thenReturn(mockPendingResult); Player.Commands commandsWithSeekToPrevious = createCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); + Player.Commands commandsWithoutSeek = createCommands(); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3); @@ -793,7 +803,7 @@ public class CastPlayerTest { ImmutableList.of(mediaItem3), /* mediaQueueItemIds= */ new int[] {3}, /* currentItemId= */ 3); - verify(mockListener).onAvailableCommandsChanged(Player.Commands.EMPTY); + verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); castPlayer.removeMediaItem(/* index= */ 0); @@ -807,6 +817,7 @@ public class CastPlayerTest { @Test public void removeMediaItem_current_notifiesAvailableCommandsChanged() { Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); + Player.Commands commandsWithoutSeek = createCommands(); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); @@ -823,7 +834,7 @@ public class CastPlayerTest { ImmutableList.of(mediaItem2), /* mediaQueueItemIds= */ new int[] {2}, /* currentItemId= */ 2); - verify(mockListener).onAvailableCommandsChanged(Player.Commands.EMPTY); + verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); } @@ -912,6 +923,7 @@ public class CastPlayerTest { private static Player.Commands createCommands(@Player.Command int... commands) { Player.Commands.Builder builder = new Player.Commands.Builder(); + builder.addAll(COMMAND_PLAY_PAUSE, COMMAND_PREPARE_STOP_RELEASE); for (int command : commands) { builder.add(command); } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java b/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java index baf0623036..def5629bfe 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java @@ -24,6 +24,9 @@ import java.util.List; /** Abstract base {@link Player} which implements common implementation independent methods. */ public abstract class BasePlayer implements Player { + protected static final int[] PERMANENT_AVAILABLE_COMMANDS = + new int[] {COMMAND_PLAY_PAUSE, COMMAND_PREPARE_STOP_RELEASE}; + protected final Timeline.Window window; public BasePlayer() { @@ -322,6 +325,7 @@ public abstract class BasePlayer implements Player { protected Commands getAvailableCommands() { return new Commands.Builder() + .addAll(PERMANENT_AVAILABLE_COMMANDS) .addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNext() && !isPlayingAd()) .addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPrevious() && !isPlayingAd()) .build(); diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Player.java b/library/common/src/main/java/com/google/android/exoplayer2/Player.java index 40fb87de0e..fc9a3c800e 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/Player.java @@ -757,6 +757,18 @@ public interface Player { return this; } + /** + * Adds {@link Command commands}. + * + * @param commands The {@link Command commands} to add. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder addAll(@Command int... commands) { + flagsBuilder.addAll(commands); + return this; + } + /** * Builds a {@link Commands} instance. * @@ -767,9 +779,6 @@ public interface Player { } } - /** An empty set of commands. */ - public static final Commands EMPTY = new Builder().build(); - private final ExoFlags flags; private Commands(ExoFlags flags) { @@ -1037,17 +1046,27 @@ public interface Player { int EVENT_AVAILABLE_COMMANDS_CHANGED = 14; /** - * Commands that can be executed on a {@code Player}. One of {@link - * #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} or {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}. + * Commands that can be executed on a {@code Player}. One of {@link #COMMAND_PLAY_PAUSE}, {@link + * #COMMAND_PREPARE_STOP_RELEASE}, {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} or {@link + * #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}. */ @Documented @Retention(RetentionPolicy.SOURCE) - @IntDef({COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}) + @IntDef({ + COMMAND_PLAY_PAUSE, + COMMAND_PREPARE_STOP_RELEASE, + COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, + COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM + }) @interface Command {} + /** Command to start, pause or resume playback. */ + int COMMAND_PLAY_PAUSE = 1; + /** Command to prepare the player, stop playback or release the player. */ + int COMMAND_PREPARE_STOP_RELEASE = 2; /** Command to seek to the next {@link MediaItem} in the playlist. */ - int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM = 0; + int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM = 3; /** Command to seek to the previous {@link MediaItem} in the playlist. */ - int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM = 1; + int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM = 4; /** Returns the component of this player for audio output, or null if audio is not supported. */ @Nullable diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/ExoFlags.java b/library/common/src/main/java/com/google/android/exoplayer2/util/ExoFlags.java index 17418aa6b2..34faa856aa 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/ExoFlags.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/ExoFlags.java @@ -70,6 +70,20 @@ public final class ExoFlags { return this; } + /** + * Adds flags. + * + * @param flags The flags to add. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder addAll(int... flags) { + for (int flag : flags) { + add(flag); + } + return this; + } + /** * Builds an {@link ExoFlags} instance. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 6539b630fd..d823975595 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -174,7 +174,7 @@ import java.util.List; new ExoTrackSelection[renderers.length], /* info= */ null); period = new Timeline.Period(); - availableCommands = Commands.EMPTY; + availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build(); maskingWindowIndex = C.INDEX_UNSET; playbackInfoUpdateHandler = clock.createHandler(applicationLooper, /* callback= */ null); playbackInfoUpdateListener = diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index ba29b5fdbd..31cf947884 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2; +import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE; +import static com.google.android.exoplayer2.Player.COMMAND_PREPARE_STOP_RELEASE; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static com.google.android.exoplayer2.robolectric.RobolectricUtil.runMainLooperUntil; @@ -8080,6 +8082,14 @@ public final class ExoPlayerTest { assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse(); } + @Test + public void isCommandAvailable_containsPermanentCommands() { + ExoPlayer player = new TestExoPlayerBuilder(context).build(); + + assertThat(player.isCommandAvailable(COMMAND_PLAY_PAUSE)).isTrue(); + assertThat(player.isCommandAvailable(COMMAND_PREPARE_STOP_RELEASE)).isTrue(); + } + @Test public void isCommandAvailable_whenPlayingAd_isFalseForSeekCommands() throws Exception { AdPlaybackState adPlaybackState = @@ -8262,6 +8272,7 @@ public final class ExoPlayerTest { @Test public void removeMediaItem_atTheEnd_notifiesAvailableCommandsChanged() { Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); + Player.Commands commandsWithoutSeek = createCommands(); Player.EventListener mockListener = mock(Player.EventListener.class); ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addListener(mockListener); @@ -8275,7 +8286,7 @@ public final class ExoPlayerTest { verify(mockListener).onAvailableCommandsChanged(any()); player.removeMediaItem(/* index= */ 1); - verify(mockListener).onAvailableCommandsChanged(Player.Commands.EMPTY); + verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); player.removeMediaItem(/* index= */ 0); @@ -8286,6 +8297,7 @@ public final class ExoPlayerTest { public void removeMediaItem_atTheStart_notifiesAvailableCommandsChanged() { Player.Commands commandsWithSeekToPrevious = createCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); + Player.Commands commandsWithoutSeek = createCommands(); Player.EventListener mockListener = mock(Player.EventListener.class); ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addListener(mockListener); @@ -8300,7 +8312,7 @@ public final class ExoPlayerTest { verify(mockListener).onAvailableCommandsChanged(any()); player.removeMediaItem(/* index= */ 0); - verify(mockListener).onAvailableCommandsChanged(Player.Commands.EMPTY); + verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); player.removeMediaItem(/* index= */ 0); @@ -8310,6 +8322,7 @@ public final class ExoPlayerTest { @Test public void removeMediaItem_current_notifiesAvailableCommandsChanged() { Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); + Player.Commands commandsWithoutSeek = createCommands(); Player.EventListener mockListener = mock(Player.EventListener.class); ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addListener(mockListener); @@ -8319,7 +8332,7 @@ public final class ExoPlayerTest { verify(mockListener).onAvailableCommandsChanged(any()); player.removeMediaItem(/* index= */ 0); - verify(mockListener).onAvailableCommandsChanged(Player.Commands.EMPTY); + verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); } @@ -9313,6 +9326,7 @@ public final class ExoPlayerTest { private static Player.Commands createCommands(@Player.Command int... commands) { Player.Commands.Builder builder = new Player.Commands.Builder(); + builder.addAll(COMMAND_PLAY_PAUSE, COMMAND_PREPARE_STOP_RELEASE); for (int command : commands) { builder.add(command); }