diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaController.java b/libraries/session/src/main/java/androidx/media3/session/MediaController.java
index 16487eedaf..12f00cbe2e 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaController.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaController.java
@@ -410,6 +410,8 @@ public class MediaController implements Player {
* Called when the {@linkplain #getCustomLayout() custom layout} changed.
*
*
This method will be deprecated, prefer to use {@link #onMediaButtonPreferencesChanged}.
+ * Note that the media button preferences use {@link CommandButton#slots} to define the allowed
+ * button placement.
*
*
The custom layout can change when either the session {@linkplain
* MediaSession#setCustomLayout changes the custom layout}, or when the session {@linkplain
@@ -1116,6 +1118,8 @@ public class MediaController implements Player {
* Returns the custom layout.
*
*
This method will be deprecated, prefer to use {@link #getMediaButtonPreferences()} instead.
+ * Note that the media button preferences use {@link CommandButton#slots} to define the allowed
+ * button placement.
*
*
After being connected, a change of the custom layout is reported with {@link
* Listener#onCustomLayoutChanged(MediaController, List)}.
@@ -1127,7 +1131,8 @@ public class MediaController implements Player {
*/
@UnstableApi
public final ImmutableList getCustomLayout() {
- return getMediaButtonPreferences();
+ verifyApplicationThread();
+ return isConnected() ? impl.getCustomLayout() : ImmutableList.of();
}
/**
@@ -2208,6 +2213,8 @@ public class MediaController implements Player {
ImmutableList getMediaButtonPreferences();
+ ImmutableList getCustomLayout();
+
ImmutableList getCommandButtonsForMediaItem(MediaItem mediaItem);
Bundle getSessionExtras();
diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
index c3b4936cad..27dc593a0f 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
@@ -93,7 +93,6 @@ import com.google.common.util.concurrent.MoreExecutors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -128,6 +127,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
private ImmutableList customLayoutOriginal;
private ImmutableList mediaButtonPreferencesOriginal;
private ImmutableList resolvedMediaButtonPreferences;
+ private ImmutableList resolvedCustomLayout;
private ImmutableMap commandButtonsForMediaItemsMap;
private SessionCommands sessionCommands;
private Commands playerCommandsFromSession;
@@ -158,6 +158,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
customLayoutOriginal = ImmutableList.of();
mediaButtonPreferencesOriginal = ImmutableList.of();
resolvedMediaButtonPreferences = ImmutableList.of();
+ resolvedCustomLayout = ImmutableList.of();
commandButtonsForMediaItemsMap = ImmutableMap.of();
playerCommandsFromSession = Commands.EMPTY;
playerCommandsFromPlayer = Commands.EMPTY;
@@ -751,6 +752,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
return resolvedMediaButtonPreferences;
}
+ @Override
+ public ImmutableList getCustomLayout() {
+ return resolvedCustomLayout;
+ }
+
@Override
public ImmutableList getCommandButtonsForMediaItem(MediaItem mediaItem) {
ImmutableList supportedActions = mediaItem.mediaMetadata.supportedCommands;
@@ -2662,6 +2668,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
sessionCommands,
intersectedPlayerCommands,
result.sessionExtras);
+ resolvedCustomLayout =
+ resolveCustomLayout(
+ resolvedMediaButtonPreferences, result.sessionExtras, intersectedPlayerCommands);
ImmutableMap.Builder commandButtonsForMediaItems =
new ImmutableMap.Builder<>();
for (int i = 0; i < result.commandButtonsForMediaItems.size(); i++) {
@@ -2842,8 +2851,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
!Util.areEqual(intersectedPlayerCommands, prevIntersectedPlayerCommands);
}
boolean mediaButtonPreferencesChanged = false;
+ boolean customLayoutChanged = false;
if (sessionCommandsChanged || intersectedPlayerCommandsChanged) {
ImmutableList oldMediaButtonPreferences = resolvedMediaButtonPreferences;
+ ImmutableList oldCustomLayout = resolvedCustomLayout;
resolvedMediaButtonPreferences =
resolveMediaButtonPreferences(
mediaButtonPreferencesOriginal,
@@ -2851,8 +2862,12 @@ import org.checkerframework.checker.nullness.qual.NonNull;
sessionCommands,
intersectedPlayerCommands,
sessionExtras);
+ resolvedCustomLayout =
+ resolveCustomLayout(
+ resolvedMediaButtonPreferences, sessionExtras, intersectedPlayerCommands);
mediaButtonPreferencesChanged =
!resolvedMediaButtonPreferences.equals(oldMediaButtonPreferences);
+ customLayoutChanged = !resolvedCustomLayout.equals(oldCustomLayout);
}
if (intersectedPlayerCommandsChanged) {
listeners.sendEvent(
@@ -2865,14 +2880,17 @@ import org.checkerframework.checker.nullness.qual.NonNull;
listener ->
listener.onAvailableSessionCommandsChanged(getInstance(), sessionCommands));
}
+ if (customLayoutChanged) {
+ getInstance()
+ .notifyControllerListener(
+ listener -> listener.onCustomLayoutChanged(getInstance(), resolvedCustomLayout));
+ }
if (mediaButtonPreferencesChanged) {
getInstance()
.notifyControllerListener(
- listener -> {
- listener.onCustomLayoutChanged(getInstance(), resolvedMediaButtonPreferences);
- listener.onMediaButtonPreferencesChanged(
- getInstance(), resolvedMediaButtonPreferences);
- });
+ listener ->
+ listener.onMediaButtonPreferencesChanged(
+ getInstance(), resolvedMediaButtonPreferences));
}
}
@@ -2891,8 +2909,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
boolean intersectedPlayerCommandsChanged =
!Util.areEqual(intersectedPlayerCommands, prevIntersectedPlayerCommands);
boolean mediaButtonPreferencesChanged = false;
+ boolean customLayoutChanged = false;
if (intersectedPlayerCommandsChanged) {
ImmutableList oldMediaButtonPreferences = resolvedMediaButtonPreferences;
+ ImmutableList oldCustomLayout = resolvedCustomLayout;
resolvedMediaButtonPreferences =
resolveMediaButtonPreferences(
mediaButtonPreferencesOriginal,
@@ -2900,20 +2920,27 @@ import org.checkerframework.checker.nullness.qual.NonNull;
sessionCommands,
intersectedPlayerCommands,
sessionExtras);
+ resolvedCustomLayout =
+ resolveCustomLayout(
+ resolvedMediaButtonPreferences, sessionExtras, intersectedPlayerCommands);
mediaButtonPreferencesChanged =
!resolvedMediaButtonPreferences.equals(oldMediaButtonPreferences);
+ customLayoutChanged = !resolvedCustomLayout.equals(oldCustomLayout);
listeners.sendEvent(
/* eventFlag= */ Player.EVENT_AVAILABLE_COMMANDS_CHANGED,
listener -> listener.onAvailableCommandsChanged(intersectedPlayerCommands));
}
+ if (customLayoutChanged) {
+ getInstance()
+ .notifyControllerListener(
+ listener -> listener.onCustomLayoutChanged(getInstance(), resolvedCustomLayout));
+ }
if (mediaButtonPreferencesChanged) {
getInstance()
.notifyControllerListener(
- listener -> {
- listener.onCustomLayoutChanged(getInstance(), resolvedMediaButtonPreferences);
- listener.onMediaButtonPreferencesChanged(
- getInstance(), resolvedMediaButtonPreferences);
- });
+ listener ->
+ listener.onMediaButtonPreferencesChanged(
+ getInstance(), resolvedMediaButtonPreferences));
}
}
@@ -2922,6 +2949,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
return;
}
ImmutableList oldMediaButtonPreferences = resolvedMediaButtonPreferences;
+ ImmutableList oldCustomLayout = resolvedCustomLayout;
customLayoutOriginal = ImmutableList.copyOf(layout);
resolvedMediaButtonPreferences =
resolveMediaButtonPreferences(
@@ -2930,17 +2958,23 @@ import org.checkerframework.checker.nullness.qual.NonNull;
sessionCommands,
intersectedPlayerCommands,
sessionExtras);
+ resolvedCustomLayout =
+ resolveCustomLayout(
+ resolvedMediaButtonPreferences, sessionExtras, intersectedPlayerCommands);
boolean mediaButtonPreferencesChanged =
- !Objects.equals(resolvedMediaButtonPreferences, oldMediaButtonPreferences);
+ !resolvedMediaButtonPreferences.equals(oldMediaButtonPreferences);
+ boolean customLayoutChanged = !resolvedCustomLayout.equals(oldCustomLayout);
getInstance()
.notifyControllerListener(
listener -> {
ListenableFuture future =
checkNotNull(
- listener.onSetCustomLayout(getInstance(), resolvedMediaButtonPreferences),
+ listener.onSetCustomLayout(getInstance(), resolvedCustomLayout),
"MediaController.Listener#onSetCustomLayout() must not return null");
+ if (customLayoutChanged) {
+ listener.onCustomLayoutChanged(getInstance(), resolvedCustomLayout);
+ }
if (mediaButtonPreferencesChanged) {
- listener.onCustomLayoutChanged(getInstance(), resolvedMediaButtonPreferences);
listener.onMediaButtonPreferencesChanged(
getInstance(), resolvedMediaButtonPreferences);
}
@@ -2953,6 +2987,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
return;
}
ImmutableList oldMediaButtonPreferences = resolvedMediaButtonPreferences;
+ ImmutableList oldCustomLayout = resolvedCustomLayout;
mediaButtonPreferencesOriginal = ImmutableList.copyOf(mediaButtonPreferences);
resolvedMediaButtonPreferences =
resolveMediaButtonPreferences(
@@ -2961,17 +2996,23 @@ import org.checkerframework.checker.nullness.qual.NonNull;
sessionCommands,
intersectedPlayerCommands,
sessionExtras);
+ resolvedCustomLayout =
+ resolveCustomLayout(
+ resolvedMediaButtonPreferences, sessionExtras, intersectedPlayerCommands);
boolean mediaButtonPreferencesChanged =
- !Objects.equals(resolvedMediaButtonPreferences, oldMediaButtonPreferences);
+ !resolvedMediaButtonPreferences.equals(oldMediaButtonPreferences);
+ boolean customLayoutChanged = !resolvedCustomLayout.equals(oldCustomLayout);
getInstance()
.notifyControllerListener(
listener -> {
ListenableFuture future =
checkNotNull(
- listener.onSetCustomLayout(getInstance(), resolvedMediaButtonPreferences),
+ listener.onSetCustomLayout(getInstance(), resolvedCustomLayout),
"MediaController.Listener#onSetCustomLayout() must not return null");
+ if (customLayoutChanged) {
+ listener.onCustomLayoutChanged(getInstance(), resolvedCustomLayout);
+ }
if (mediaButtonPreferencesChanged) {
- listener.onCustomLayoutChanged(getInstance(), resolvedMediaButtonPreferences);
listener.onMediaButtonPreferencesChanged(
getInstance(), resolvedMediaButtonPreferences);
}
@@ -2984,6 +3025,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
return;
}
ImmutableList oldMediaButtonPreferences = resolvedMediaButtonPreferences;
+ ImmutableList oldCustomLayout = resolvedCustomLayout;
sessionExtras = extras;
resolvedMediaButtonPreferences =
resolveMediaButtonPreferences(
@@ -2992,14 +3034,20 @@ import org.checkerframework.checker.nullness.qual.NonNull;
sessionCommands,
intersectedPlayerCommands,
sessionExtras);
+ resolvedCustomLayout =
+ resolveCustomLayout(
+ resolvedMediaButtonPreferences, sessionExtras, intersectedPlayerCommands);
boolean mediaButtonPreferencesChanged =
- !Objects.equals(resolvedMediaButtonPreferences, oldMediaButtonPreferences);
+ !resolvedMediaButtonPreferences.equals(oldMediaButtonPreferences);
+ boolean customLayoutChanged = !resolvedCustomLayout.equals(oldCustomLayout);
getInstance()
.notifyControllerListener(
listener -> {
listener.onExtrasChanged(getInstance(), extras);
+ if (customLayoutChanged) {
+ listener.onCustomLayoutChanged(getInstance(), resolvedCustomLayout);
+ }
if (mediaButtonPreferencesChanged) {
- listener.onCustomLayoutChanged(getInstance(), resolvedMediaButtonPreferences);
listener.onMediaButtonPreferencesChanged(
getInstance(), resolvedMediaButtonPreferences);
}
@@ -3365,6 +3413,22 @@ import org.checkerframework.checker.nullness.qual.NonNull;
resolvedButtons, sessionCommands, playerCommands);
}
+ private static ImmutableList resolveCustomLayout(
+ List mediaButtonPreferences,
+ Bundle sessionExtras,
+ Player.Commands availableCommands) {
+ boolean backSlotAllowed =
+ !sessionExtras.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV)
+ && !availableCommands.containsAny(
+ Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, Player.COMMAND_SEEK_TO_PREVIOUS);
+ boolean forwardSlotAllowed =
+ !sessionExtras.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT)
+ && !availableCommands.containsAny(
+ Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, Player.COMMAND_SEEK_TO_NEXT);
+ return CommandButton.getCustomLayoutFromMediaButtonPreferences(
+ mediaButtonPreferences, backSlotAllowed, forwardSlotAllowed);
+ }
+
private static Commands createIntersectedCommandsEnsuringCommandReleaseAvailable(
Commands commandFromSession, Commands commandsFromPlayer) {
Commands intersectedCommands = MediaUtils.intersect(commandFromSession, commandsFromPlayer);
diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java
index 746ff3f3c8..c32362c439 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java
@@ -437,6 +437,11 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization;
return controllerInfo.mediaButtonPreferences;
}
+ @Override
+ public ImmutableList getCustomLayout() {
+ return controllerInfo.mediaButtonPreferences;
+ }
+
@Override
public Bundle getSessionExtras() {
return controllerInfo.sessionExtras;
diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java
index 5e962d3f72..b39524fbef 100644
--- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java
+++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java
@@ -216,8 +216,8 @@ public class MediaControllerTest {
assertThat(threadTestRule.getHandler().postAndSync(controller::getCustomLayout))
.containsExactly(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
- withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withBackSlot(button1.copyWithIsEnabled(true)),
+ withForwardSlot(button2.copyWithIsEnabled(false)),
withOverflowSlot(button3.copyWithIsEnabled(false)),
withOverflowSlot(button4.copyWithIsEnabled(true)),
withOverflowSlot(button5.copyWithIsEnabled(false)))
@@ -301,13 +301,13 @@ public class MediaControllerTest {
assertThat(initialCustomLayoutFromGetter)
.containsExactly(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
- withForwardOverflowSlot(button3.copyWithIsEnabled(false)))
+ withBackSlot(button1.copyWithIsEnabled(true)),
+ withForwardSlot(button3.copyWithIsEnabled(false)))
.inOrder();
ImmutableList expectedNewButtons =
ImmutableList.of(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
- withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withBackSlot(button1.copyWithIsEnabled(true)),
+ withForwardSlot(button2.copyWithIsEnabled(false)),
withOverflowSlot(button4.copyWithIsEnabled(false)),
withOverflowSlot(button5.copyWithIsEnabled(true)),
withOverflowSlot(button6.copyWithIsEnabled(false)));
@@ -378,37 +378,37 @@ public class MediaControllerTest {
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(initialCustomLayout)
.containsExactly(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
- withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withBackSlot(button1.copyWithIsEnabled(true)),
+ withForwardSlot(button2.copyWithIsEnabled(false)),
withOverflowSlot(button3.copyWithIsEnabled(true)),
withOverflowSlot(button4.copyWithIsEnabled(false)));
assertThat(reportedCustomLayoutChanged).hasSize(2);
assertThat(reportedCustomLayoutChanged.get(0))
.containsExactly(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
- withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withBackSlot(button1.copyWithIsEnabled(false)),
+ withForwardSlot(button2.copyWithIsEnabled(false)),
withOverflowSlot(button3.copyWithIsEnabled(false)),
withOverflowSlot(button4.copyWithIsEnabled(false)))
.inOrder();
assertThat(reportedCustomLayoutChanged.get(1))
.containsExactly(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
- withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withBackSlot(button1.copyWithIsEnabled(false)),
+ withForwardSlot(button2.copyWithIsEnabled(false)),
withOverflowSlot(button3.copyWithIsEnabled(false)),
withOverflowSlot(button4.copyWithIsEnabled(true)))
.inOrder();
assertThat(getterCustomLayoutChanged).hasSize(2);
assertThat(getterCustomLayoutChanged.get(0))
.containsExactly(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
- withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withBackSlot(button1.copyWithIsEnabled(false)),
+ withForwardSlot(button2.copyWithIsEnabled(false)),
withOverflowSlot(button3.copyWithIsEnabled(false)),
withOverflowSlot(button4.copyWithIsEnabled(false)))
.inOrder();
assertThat(getterCustomLayoutChanged.get(1))
.containsExactly(
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
- withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withBackSlot(button1.copyWithIsEnabled(false)),
+ withForwardSlot(button2.copyWithIsEnabled(false)),
withOverflowSlot(button3.copyWithIsEnabled(false)),
withOverflowSlot(button4.copyWithIsEnabled(true)))
.inOrder();
@@ -453,18 +453,17 @@ public class MediaControllerTest {
new Player.Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build());
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
- assertThat(initialCustomLayout)
- .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(true)));
+ assertThat(initialCustomLayout).containsExactly(withBackSlot(button.copyWithIsEnabled(true)));
assertThat(reportedCustomLayouts).hasSize(2);
assertThat(reportedCustomLayouts.get(0))
- .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(false)));
+ .containsExactly(withBackSlot(button.copyWithIsEnabled(false)));
assertThat(reportedCustomLayouts.get(1))
- .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(true)));
+ .containsExactly(withBackSlot(button.copyWithIsEnabled(true)));
assertThat(getterCustomLayouts).hasSize(2);
assertThat(getterCustomLayouts.get(0))
- .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(false)));
+ .containsExactly(withBackSlot(button.copyWithIsEnabled(false)));
assertThat(getterCustomLayouts.get(1))
- .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(true)));
+ .containsExactly(withBackSlot(button.copyWithIsEnabled(true)));
session.cleanUp();
}
@@ -534,14 +533,10 @@ public class MediaControllerTest {
session.setCustomLayout(ImmutableList.of(button1, button2));
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
- CommandButton button1EnabledBackSlot =
- withBackForwardOverflowSlot(button1.copyWithIsEnabled(true));
- CommandButton button2DisabledForwardSlot =
- withForwardOverflowSlot(button2.copyWithIsEnabled(false));
- CommandButton button3DisabledBackSlot =
- withBackForwardOverflowSlot(button3.copyWithIsEnabled(false));
- CommandButton button4DisabledForwardSlot =
- withForwardOverflowSlot(button4.copyWithIsEnabled(false));
+ CommandButton button1EnabledBackSlot = withBackSlot(button1.copyWithIsEnabled(true));
+ CommandButton button2DisabledForwardSlot = withForwardSlot(button2.copyWithIsEnabled(false));
+ CommandButton button3DisabledBackSlot = withBackSlot(button3.copyWithIsEnabled(false));
+ CommandButton button4DisabledForwardSlot = withForwardSlot(button4.copyWithIsEnabled(false));
assertThat(initialCustomLayout)
.containsExactly(button1EnabledBackSlot, button2DisabledForwardSlot)
.inOrder();
@@ -626,17 +621,11 @@ public class MediaControllerTest {
assertThat(reportedCustomLayouts)
.containsExactly(
ImmutableList.of(
- withBackForwardOverflowSlot(button1),
- withForwardOverflowSlot(button2),
- withOverflowSlot(button3)),
+ withBackSlot(button1), withForwardSlot(button2), withOverflowSlot(button3)),
ImmutableList.of(
- withBackOverflowSlot(button1),
- withOverflowSlot(button2),
- withOverflowSlot(button3)),
+ withBackSlot(button1), withOverflowSlot(button2), withOverflowSlot(button3)),
ImmutableList.of(
- withForwardOverflowSlot(button1),
- withOverflowSlot(button2),
- withOverflowSlot(button3)),
+ withForwardSlot(button1), withOverflowSlot(button2), withOverflowSlot(button3)),
ImmutableList.of(
withOverflowSlot(button1), withOverflowSlot(button2), withOverflowSlot(button3)));
session.cleanUp();
@@ -700,6 +689,361 @@ public class MediaControllerTest {
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(reportedCustomLayouts)
+ .containsExactly(
+ ImmutableList.of(
+ withBackSlot(button1), withForwardSlot(button2), withOverflowSlot(button3)),
+ ImmutableList.of(
+ withBackSlot(button1), withOverflowSlot(button2), withOverflowSlot(button3)),
+ ImmutableList.of(
+ withForwardSlot(button1), withOverflowSlot(button2), withOverflowSlot(button3)),
+ ImmutableList.of(
+ withOverflowSlot(button1), withOverflowSlot(button2), withOverflowSlot(button3)));
+ session.cleanUp();
+ }
+
+ @Test
+ public void getMediaButtonPreferences_customLayoutBuiltWithSession_includedOnConnect()
+ throws Exception {
+ RemoteMediaSession session =
+ createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, /* tokenExtras= */ null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button1")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button2")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ CommandButton button5 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button5")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button2, button3, button4, button5));
+ MediaController controller = controllerTestRule.createController(session.getToken());
+
+ assertThat(threadTestRule.getHandler().postAndSync(controller::getMediaButtonPreferences))
+ .containsExactly(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
+ withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(true)),
+ withOverflowSlot(button5.copyWithIsEnabled(false)))
+ .inOrder();
+
+ session.cleanUp();
+ }
+
+ @Test
+ public void getMediaButtonPreferences_sessionSetCustomLayout_mediaButtonPreferencesChanged()
+ throws Exception {
+ RemoteMediaSession session =
+ createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, /* tokenExtras= */ null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button1")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button2")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command4", Bundle.EMPTY))
+ .build();
+ CommandButton button5 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button5")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ CommandButton button6 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button6")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button3));
+ CountDownLatch latch = new CountDownLatch(1);
+ AtomicReference> reportedMediaButtonPreferences = new AtomicReference<>();
+ MediaController controller =
+ controllerTestRule.createController(
+ session.getToken(),
+ Bundle.EMPTY,
+ new MediaController.Listener() {
+ @Override
+ public void onMediaButtonPreferencesChanged(
+ MediaController controller1, List mediaButtonPreferences) {
+ reportedMediaButtonPreferences.set(mediaButtonPreferences);
+ latch.countDown();
+ }
+ });
+ ImmutableList initialMediaButtonPreferencesFromGetter =
+ threadTestRule.getHandler().postAndSync(controller::getMediaButtonPreferences);
+ session.setCustomLayout(ImmutableList.of(button1, button2, button4, button5, button6));
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+
+ ImmutableList newMediaButtonPreferencesFromGetter =
+ threadTestRule.getHandler().postAndSync(controller::getMediaButtonPreferences);
+
+ assertThat(initialMediaButtonPreferencesFromGetter)
+ .containsExactly(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
+ withForwardOverflowSlot(button3.copyWithIsEnabled(false)))
+ .inOrder();
+ ImmutableList expectedNewButtons =
+ ImmutableList.of(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
+ withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)),
+ withOverflowSlot(button5.copyWithIsEnabled(true)),
+ withOverflowSlot(button6.copyWithIsEnabled(false)));
+ assertThat(newMediaButtonPreferencesFromGetter)
+ .containsExactlyElementsIn(expectedNewButtons)
+ .inOrder();
+ assertThat(reportedMediaButtonPreferences.get())
+ .containsExactlyElementsIn(expectedNewButtons)
+ .inOrder();
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getMediaButtonPreferences_setAvailableCommandsOnSessionAfterSetCustomLayout_reportsMediaButtonPreferencesChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button1")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button2")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button2, button3, button4));
+ CountDownLatch latch = new CountDownLatch(2);
+ List> reportedMediaButtonPreferences = new ArrayList<>();
+ List> getterMediaButtonPreferences = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onMediaButtonPreferencesChanged(
+ MediaController controller, List mediaButtonPreferences) {
+ reportedMediaButtonPreferences.add(mediaButtonPreferences);
+ getterMediaButtonPreferences.add(controller.getMediaButtonPreferences());
+ latch.countDown();
+ }
+ };
+ MediaController controller =
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+ ImmutableList initialMediaButtonPreferences =
+ threadTestRule.getHandler().postAndSync(controller::getMediaButtonPreferences);
+
+ // Remove commands in custom layout from available commands.
+ session.setAvailableCommands(SessionCommands.EMPTY, Player.Commands.EMPTY);
+ // Add one session and player command back.
+ session.setAvailableCommands(
+ new SessionCommands.Builder().add(button2.sessionCommand).build(),
+ new Player.Commands.Builder().add(Player.COMMAND_GET_TRACKS).build());
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(initialMediaButtonPreferences)
+ .containsExactly(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(true)),
+ withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(true)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)));
+ assertThat(reportedMediaButtonPreferences).hasSize(2);
+ assertThat(reportedMediaButtonPreferences.get(0))
+ .containsExactly(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
+ withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)))
+ .inOrder();
+ assertThat(reportedMediaButtonPreferences.get(1))
+ .containsExactly(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
+ withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(true)))
+ .inOrder();
+ assertThat(getterMediaButtonPreferences).hasSize(2);
+ assertThat(getterMediaButtonPreferences.get(0))
+ .containsExactly(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
+ withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)))
+ .inOrder();
+ assertThat(getterMediaButtonPreferences.get(1))
+ .containsExactly(
+ withBackForwardOverflowSlot(button1.copyWithIsEnabled(false)),
+ withForwardOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(true)))
+ .inOrder();
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getMediaButtonPreferences_setAvailableCommandsOnPlayerAfterSetCustomLayout_reportsMediaButtonPreferencesChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button));
+ CountDownLatch latch = new CountDownLatch(2);
+ List> reportedMediaButtonPreferences = new ArrayList<>();
+ List> getterMediaButtonPreferences = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onMediaButtonPreferencesChanged(
+ MediaController controller, List mediaButtonPreferences) {
+ reportedMediaButtonPreferences.add(mediaButtonPreferences);
+ getterMediaButtonPreferences.add(controller.getMediaButtonPreferences());
+ latch.countDown();
+ }
+ };
+ MediaController controller =
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+ ImmutableList initialMediaButtonPreferences =
+ threadTestRule.getHandler().postAndSync(controller::getMediaButtonPreferences);
+
+ // Disable player command and then add it back.
+ session.getMockPlayer().notifyAvailableCommandsChanged(Player.Commands.EMPTY);
+ session
+ .getMockPlayer()
+ .notifyAvailableCommandsChanged(
+ new Player.Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build());
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(initialMediaButtonPreferences)
+ .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(true)));
+ assertThat(reportedMediaButtonPreferences).hasSize(2);
+ assertThat(reportedMediaButtonPreferences.get(0))
+ .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(false)));
+ assertThat(reportedMediaButtonPreferences.get(1))
+ .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(true)));
+ assertThat(getterMediaButtonPreferences).hasSize(2);
+ assertThat(getterMediaButtonPreferences.get(0))
+ .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(false)));
+ assertThat(getterMediaButtonPreferences.get(1))
+ .containsExactly(withBackForwardOverflowSlot(button.copyWithIsEnabled(true)));
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getMediaButtonPreferences_setAvailablePrevNextCommandAfterSetCustomLayout_reportsMediaButtonPreferencesChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_ALBUM)
+ .setDisplayName("button1")
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_REWIND)
+ .setDisplayName("button2")
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_SHUFFLE_ON)
+ .setDisplayName("button3")
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ SessionCommands allSessionCommands =
+ new SessionCommands.Builder()
+ .add(button1.sessionCommand)
+ .add(button2.sessionCommand)
+ .add(button3.sessionCommand)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button2, button3));
+ CountDownLatch latch = new CountDownLatch(4);
+ List> reportedMediaButtonPreferences = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onMediaButtonPreferencesChanged(
+ MediaController controller, List mediaButtonPreferences) {
+ reportedMediaButtonPreferences.add(mediaButtonPreferences);
+ latch.countDown();
+ }
+ };
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+
+ session.setAvailableCommands(allSessionCommands, Player.Commands.EMPTY);
+ session.setAvailableCommands(
+ allSessionCommands, new Player.Commands.Builder().add(Player.COMMAND_SEEK_TO_NEXT).build());
+ session.setAvailableCommands(
+ allSessionCommands,
+ new Player.Commands.Builder().add(Player.COMMAND_SEEK_TO_PREVIOUS).build());
+ session.setAvailableCommands(
+ allSessionCommands,
+ new Player.Commands.Builder()
+ .addAll(Player.COMMAND_SEEK_TO_NEXT, Player.COMMAND_SEEK_TO_PREVIOUS)
+ .build());
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(reportedMediaButtonPreferences)
.containsExactly(
ImmutableList.of(
withBackForwardOverflowSlot(button1),
@@ -718,6 +1062,618 @@ public class MediaControllerTest {
session.cleanUp();
}
+ @Test
+ public void
+ getMediaButtonPreferences_setSessionExtrasForPrevNextReservationsAfterSetCustomLayout_reportsMediaButtonPreferencesChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_ALBUM)
+ .setDisplayName("button1")
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_REWIND)
+ .setDisplayName("button2")
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_SHUFFLE_ON)
+ .setDisplayName("button3")
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ SessionCommands allSessionCommands =
+ new SessionCommands.Builder()
+ .add(button1.sessionCommand)
+ .add(button2.sessionCommand)
+ .add(button3.sessionCommand)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button2, button3));
+ CountDownLatch latch = new CountDownLatch(4);
+ List> reportedMediaButtonPreferences = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onMediaButtonPreferencesChanged(
+ MediaController controller, List mediaButtonPreferences) {
+ reportedMediaButtonPreferences.add(mediaButtonPreferences);
+ latch.countDown();
+ }
+ };
+ Bundle extrasNextSlotReservation = new Bundle();
+ extrasNextSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, true);
+ Bundle extrasPrevSlotReservation = new Bundle();
+ extrasPrevSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, true);
+ Bundle extrasPrevNextSlotReservation = new Bundle();
+ extrasPrevNextSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, true);
+ extrasPrevNextSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, true);
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+
+ session.setAvailableCommands(allSessionCommands, Player.Commands.EMPTY);
+ session.setSessionExtras(extrasNextSlotReservation);
+ session.setSessionExtras(extrasPrevSlotReservation);
+ session.setSessionExtras(extrasPrevNextSlotReservation);
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(reportedMediaButtonPreferences)
+ .containsExactly(
+ ImmutableList.of(
+ withBackForwardOverflowSlot(button1),
+ withForwardOverflowSlot(button2),
+ withOverflowSlot(button3)),
+ ImmutableList.of(
+ withBackOverflowSlot(button1),
+ withOverflowSlot(button2),
+ withOverflowSlot(button3)),
+ ImmutableList.of(
+ withForwardOverflowSlot(button1),
+ withOverflowSlot(button2),
+ withOverflowSlot(button3)),
+ ImmutableList.of(
+ withOverflowSlot(button1), withOverflowSlot(button2), withOverflowSlot(button3)));
+ session.cleanUp();
+ }
+
+ @Test
+ public void getCustomLayout_mediaButtonPreferencesBuiltWithSession_includedOnConnect()
+ throws Exception {
+ RemoteMediaSession session =
+ createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, /* tokenExtras= */ null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button1")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button2")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .setSlots(CommandButton.SLOT_OVERFLOW)
+ .build();
+ CommandButton button5 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button5")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupMediaButtonPreferences(
+ session, ImmutableList.of(button1, button2, button3, button4, button5));
+ MediaController controller = controllerTestRule.createController(session.getToken());
+
+ assertThat(threadTestRule.getHandler().postAndSync(controller::getCustomLayout))
+ .containsExactly(
+ withOverflowSlot(button1.copyWithIsEnabled(true)),
+ withOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(true)),
+ withOverflowSlot(button5.copyWithIsEnabled(false)))
+ .inOrder();
+
+ session.cleanUp();
+ }
+
+ @Test
+ public void getCustomLayout_sessionSetMediaButtonPreferences_customLayoutChanged()
+ throws Exception {
+ RemoteMediaSession session =
+ createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, /* tokenExtras= */ null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button1")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button2")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command4", Bundle.EMPTY))
+ .build();
+ CommandButton button5 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button5")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .setSlots(CommandButton.SLOT_OVERFLOW)
+ .build();
+ CommandButton button6 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button6")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupMediaButtonPreferences(session, ImmutableList.of(button1, button3));
+ CountDownLatch latch = new CountDownLatch(2);
+ AtomicReference> reportedCustomLayout = new AtomicReference<>();
+ AtomicReference> reportedCustomLayoutChanged = new AtomicReference<>();
+ MediaController controller =
+ controllerTestRule.createController(
+ session.getToken(),
+ Bundle.EMPTY,
+ new MediaController.Listener() {
+ @Override
+ public ListenableFuture onSetCustomLayout(
+ MediaController controller1, List layout) {
+ latch.countDown();
+ reportedCustomLayout.set(layout);
+ return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS));
+ }
+
+ @Override
+ public void onCustomLayoutChanged(
+ MediaController controller1, List layout) {
+ reportedCustomLayoutChanged.set(layout);
+ latch.countDown();
+ }
+ });
+ ImmutableList initialCustomLayoutFromGetter =
+ threadTestRule.getHandler().postAndSync(controller::getCustomLayout);
+ session.setMediaButtonPreferences(
+ ImmutableList.of(button1, button2, button4, button5, button6));
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+
+ ImmutableList newCustomLayoutFromGetter =
+ threadTestRule.getHandler().postAndSync(controller::getCustomLayout);
+
+ assertThat(initialCustomLayoutFromGetter)
+ .containsExactly(
+ withOverflowSlot(button1.copyWithIsEnabled(true)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)))
+ .inOrder();
+ ImmutableList expectedNewButtons =
+ ImmutableList.of(
+ withOverflowSlot(button1.copyWithIsEnabled(true)),
+ withOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)),
+ withOverflowSlot(button5.copyWithIsEnabled(true)),
+ withOverflowSlot(button6.copyWithIsEnabled(false)));
+ assertThat(newCustomLayoutFromGetter).containsExactlyElementsIn(expectedNewButtons).inOrder();
+ assertThat(reportedCustomLayout.get()).containsExactlyElementsIn(expectedNewButtons).inOrder();
+ assertThat(reportedCustomLayoutChanged.get())
+ .containsExactlyElementsIn(expectedNewButtons)
+ .inOrder();
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getCustomLayout_setAvailableCommandsOnSessionAfterSetMediaButtonPreferences_reportsCustomLayoutChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button1")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button2")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .setSlots(CommandButton.SLOT_OVERFLOW)
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupMediaButtonPreferences(session, ImmutableList.of(button1, button2, button3, button4));
+ CountDownLatch latch = new CountDownLatch(2);
+ List> reportedCustomLayoutChanged = new ArrayList<>();
+ List> getterCustomLayoutChanged = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onCustomLayoutChanged(
+ MediaController controller, List layout) {
+ reportedCustomLayoutChanged.add(layout);
+ getterCustomLayoutChanged.add(controller.getCustomLayout());
+ latch.countDown();
+ }
+ };
+ MediaController controller =
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+ ImmutableList initialCustomLayout =
+ threadTestRule.getHandler().postAndSync(controller::getCustomLayout);
+
+ // Remove commands in custom layout from available commands.
+ session.setAvailableCommands(SessionCommands.EMPTY, Player.Commands.EMPTY);
+ // Add one session and player command back.
+ session.setAvailableCommands(
+ new SessionCommands.Builder().add(button2.sessionCommand).build(),
+ new Player.Commands.Builder().add(Player.COMMAND_GET_TRACKS).build());
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(initialCustomLayout)
+ .containsExactly(
+ withOverflowSlot(button1.copyWithIsEnabled(true)),
+ withOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(true)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)));
+ assertThat(reportedCustomLayoutChanged).hasSize(2);
+ assertThat(reportedCustomLayoutChanged.get(0))
+ .containsExactly(
+ withOverflowSlot(button1.copyWithIsEnabled(false)),
+ withOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)))
+ .inOrder();
+ assertThat(reportedCustomLayoutChanged.get(1))
+ .containsExactly(
+ withOverflowSlot(button1.copyWithIsEnabled(false)),
+ withOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(true)))
+ .inOrder();
+ assertThat(getterCustomLayoutChanged).hasSize(2);
+ assertThat(getterCustomLayoutChanged.get(0))
+ .containsExactly(
+ withOverflowSlot(button1.copyWithIsEnabled(false)),
+ withOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(false)))
+ .inOrder();
+ assertThat(getterCustomLayoutChanged.get(1))
+ .containsExactly(
+ withOverflowSlot(button1.copyWithIsEnabled(false)),
+ withOverflowSlot(button2.copyWithIsEnabled(false)),
+ withOverflowSlot(button3.copyWithIsEnabled(false)),
+ withOverflowSlot(button4.copyWithIsEnabled(true)))
+ .inOrder();
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getCustomLayout_setAvailableCommandsOnPlayerAfterSetMediaButtonPreferences_reportsCustomLayoutChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .setSlots(CommandButton.SLOT_OVERFLOW)
+ .build();
+ setupMediaButtonPreferences(session, ImmutableList.of(button));
+ CountDownLatch latch = new CountDownLatch(2);
+ List> reportedCustomLayouts = new ArrayList<>();
+ List> getterCustomLayouts = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onCustomLayoutChanged(
+ MediaController controller, List layout) {
+ reportedCustomLayouts.add(layout);
+ getterCustomLayouts.add(controller.getCustomLayout());
+ latch.countDown();
+ }
+ };
+ MediaController controller =
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+ ImmutableList initialCustomLayout =
+ threadTestRule.getHandler().postAndSync(controller::getCustomLayout);
+
+ // Disable player command and then add it back.
+ session.getMockPlayer().notifyAvailableCommandsChanged(Player.Commands.EMPTY);
+ session
+ .getMockPlayer()
+ .notifyAvailableCommandsChanged(
+ new Player.Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build());
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(initialCustomLayout)
+ .containsExactly(withOverflowSlot(button.copyWithIsEnabled(true)));
+ assertThat(reportedCustomLayouts).hasSize(2);
+ assertThat(reportedCustomLayouts.get(0))
+ .containsExactly(withOverflowSlot(button.copyWithIsEnabled(false)));
+ assertThat(reportedCustomLayouts.get(1))
+ .containsExactly(withOverflowSlot(button.copyWithIsEnabled(true)));
+ assertThat(getterCustomLayouts).hasSize(2);
+ assertThat(getterCustomLayouts.get(0))
+ .containsExactly(withOverflowSlot(button.copyWithIsEnabled(false)));
+ assertThat(getterCustomLayouts.get(1))
+ .containsExactly(withOverflowSlot(button.copyWithIsEnabled(true)));
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getCustomLayout_sessionSetMediaButtonPreferencesNoChange_listenerNotCalledWithEqualLayout()
+ throws Exception {
+ RemoteMediaSession session =
+ createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, /* tokenExtras= */ null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button1")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button2")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder(CommandButton.ICON_UNDEFINED)
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(new SessionCommand("command4", Bundle.EMPTY))
+ .build();
+ setupMediaButtonPreferences(session, ImmutableList.of(button1, button2));
+ CountDownLatch latch = new CountDownLatch(5);
+ List> reportedCustomLayout = new ArrayList<>();
+ List> getterCustomLayout = new ArrayList<>();
+ List> reportedCustomLayoutChanged = new ArrayList<>();
+ List> getterCustomLayoutChanged = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public ListenableFuture onSetCustomLayout(
+ MediaController controller, List layout) {
+ reportedCustomLayout.add(layout);
+ getterCustomLayout.add(controller.getCustomLayout());
+ latch.countDown();
+ return MediaController.Listener.super.onSetCustomLayout(controller, layout);
+ }
+
+ @Override
+ public void onCustomLayoutChanged(
+ MediaController controller, List layout) {
+ reportedCustomLayoutChanged.add(layout);
+ getterCustomLayoutChanged.add(controller.getCustomLayout());
+ latch.countDown();
+ }
+ };
+ MediaController controller =
+ controllerTestRule.createController(session.getToken(), Bundle.EMPTY, listener);
+ ImmutableList initialCustomLayout =
+ threadTestRule.getHandler().postAndSync(controller::getCustomLayout);
+
+ // First call does not trigger onCustomLayoutChanged.
+ session.setMediaButtonPreferences(ImmutableList.of(button1, button2));
+ session.setMediaButtonPreferences(ImmutableList.of(button3, button4));
+ session.setMediaButtonPreferences(ImmutableList.of(button1, button2));
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ CommandButton button1Enabled = withOverflowSlot(button1.copyWithIsEnabled(true));
+ CommandButton button2Disabled = withOverflowSlot(button2.copyWithIsEnabled(false));
+ CommandButton button3Disabled = withOverflowSlot(button3.copyWithIsEnabled(false));
+ CommandButton button4Disabled = withOverflowSlot(button4.copyWithIsEnabled(false));
+ assertThat(initialCustomLayout).containsExactly(button1Enabled, button2Disabled).inOrder();
+ assertThat(reportedCustomLayout)
+ .containsExactly(
+ ImmutableList.of(button1Enabled, button2Disabled),
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
+ .inOrder();
+ assertThat(getterCustomLayout)
+ .containsExactly(
+ ImmutableList.of(button1Enabled, button2Disabled),
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
+ .inOrder();
+ assertThat(reportedCustomLayoutChanged)
+ .containsExactly(
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
+ .inOrder();
+ assertThat(getterCustomLayoutChanged)
+ .containsExactly(
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
+ .inOrder();
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getCustomLayout_setAvailablePrevNextCommandAfterSetMediaButtonPreferences_reportsCustomLayoutChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_ALBUM)
+ .setDisplayName("button1")
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .setSlots(CommandButton.SLOT_FORWARD)
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_REWIND)
+ .setDisplayName("button2")
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .setSlots(CommandButton.SLOT_BACK)
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_SHUFFLE_ON)
+ .setDisplayName("button3")
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ SessionCommands allSessionCommands =
+ new SessionCommands.Builder()
+ .add(button1.sessionCommand)
+ .add(button2.sessionCommand)
+ .add(button3.sessionCommand)
+ .build();
+ setupMediaButtonPreferences(session, ImmutableList.of(button1, button2, button3));
+ CountDownLatch latch = new CountDownLatch(4);
+ List> reportedCustomLayouts = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onCustomLayoutChanged(
+ MediaController controller, List layout) {
+ reportedCustomLayouts.add(layout);
+ latch.countDown();
+ }
+ };
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+
+ session.setAvailableCommands(allSessionCommands, Player.Commands.EMPTY);
+ session.setAvailableCommands(
+ allSessionCommands, new Player.Commands.Builder().add(Player.COMMAND_SEEK_TO_NEXT).build());
+ session.setAvailableCommands(
+ allSessionCommands,
+ new Player.Commands.Builder().add(Player.COMMAND_SEEK_TO_PREVIOUS).build());
+ session.setAvailableCommands(
+ allSessionCommands,
+ new Player.Commands.Builder()
+ .addAll(Player.COMMAND_SEEK_TO_NEXT, Player.COMMAND_SEEK_TO_PREVIOUS)
+ .build());
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(reportedCustomLayouts)
+ .containsExactly(
+ ImmutableList.of(
+ withBackSlot(button2), withForwardSlot(button1), withOverflowSlot(button3)),
+ ImmutableList.of(withBackSlot(button2), withOverflowSlot(button3)),
+ ImmutableList.of(withForwardSlot(button1), withOverflowSlot(button3)),
+ ImmutableList.of(withOverflowSlot(button3)));
+ session.cleanUp();
+ }
+
+ @Test
+ public void
+ getCustomLayout_setSessionExtrasForPrevNextReservationsAfterSetMediaButtonPreferences_reportsCustomLayoutChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button1 =
+ new CommandButton.Builder(CommandButton.ICON_ALBUM)
+ .setDisplayName("button1")
+ .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
+ .setSlots(CommandButton.SLOT_FORWARD)
+ .build();
+ CommandButton button2 =
+ new CommandButton.Builder(CommandButton.ICON_REWIND)
+ .setDisplayName("button2")
+ .setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
+ .setSlots(CommandButton.SLOT_BACK)
+ .build();
+ CommandButton button3 =
+ new CommandButton.Builder(CommandButton.ICON_SHUFFLE_ON)
+ .setDisplayName("button3")
+ .setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
+ .build();
+ SessionCommands allSessionCommands =
+ new SessionCommands.Builder()
+ .add(button1.sessionCommand)
+ .add(button2.sessionCommand)
+ .add(button3.sessionCommand)
+ .build();
+ setupMediaButtonPreferences(session, ImmutableList.of(button1, button2, button3));
+ CountDownLatch latch = new CountDownLatch(4);
+ List> reportedCustomLayouts = new ArrayList<>();
+ MediaController.Listener listener =
+ new MediaController.Listener() {
+ @Override
+ public void onCustomLayoutChanged(
+ MediaController controller, List layout) {
+ reportedCustomLayouts.add(layout);
+ latch.countDown();
+ }
+ };
+ Bundle extrasNextSlotReservation = new Bundle();
+ extrasNextSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, true);
+ Bundle extrasPrevSlotReservation = new Bundle();
+ extrasPrevSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, true);
+ Bundle extrasPrevNextSlotReservation = new Bundle();
+ extrasPrevNextSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, true);
+ extrasPrevNextSlotReservation.putBoolean(
+ MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, true);
+ controllerTestRule.createController(
+ session.getToken(), /* connectionHints= */ Bundle.EMPTY, listener);
+
+ session.setAvailableCommands(allSessionCommands, Player.Commands.EMPTY);
+ session.setSessionExtras(extrasNextSlotReservation);
+ session.setSessionExtras(extrasPrevSlotReservation);
+ session.setSessionExtras(extrasPrevNextSlotReservation);
+
+ assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
+ assertThat(reportedCustomLayouts)
+ .containsExactly(
+ ImmutableList.of(
+ withBackSlot(button2), withForwardSlot(button1), withOverflowSlot(button3)),
+ ImmutableList.of(withBackSlot(button2), withOverflowSlot(button3)),
+ ImmutableList.of(withForwardSlot(button1), withOverflowSlot(button3)),
+ ImmutableList.of(withOverflowSlot(button3)));
+ session.cleanUp();
+ }
+
@Test
public void getMediaButtonPreferences_mediaButtonPreferencesBuiltWithSession_includedOnConnect()
throws Exception {
@@ -2551,7 +3507,7 @@ public class MediaControllerTest {
}
private void setupCustomLayout(RemoteMediaSession session, List customLayout)
- throws RemoteException, InterruptedException, Exception {
+ throws Exception {
CountDownLatch latch = new CountDownLatch(1);
controllerTestRule.createController(
session.getToken(),
@@ -2568,8 +3524,7 @@ public class MediaControllerTest {
}
private void setupMediaButtonPreferences(
- RemoteMediaSession session, List mediaButtonPreferences)
- throws RemoteException, InterruptedException, Exception {
+ RemoteMediaSession session, List mediaButtonPreferences) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
controllerTestRule.createController(
session.getToken(),
@@ -2601,6 +3556,14 @@ public class MediaControllerTest {
ImmutableIntArray.of(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW));
}
+ private static CommandButton withBackSlot(CommandButton button) {
+ return button.copyWithSlots(ImmutableIntArray.of(CommandButton.SLOT_BACK));
+ }
+
+ private static CommandButton withForwardSlot(CommandButton button) {
+ return button.copyWithSlots(ImmutableIntArray.of(CommandButton.SLOT_FORWARD));
+ }
+
private static CommandButton withOverflowSlot(CommandButton button) {
return button.copyWithSlots(ImmutableIntArray.of(CommandButton.SLOT_OVERFLOW));
}
diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java
index a133829d85..ee847e6eb9 100644
--- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java
+++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java
@@ -335,8 +335,7 @@ public class MediaSessionServiceTest {
.containsExactly(
button1
.copyWithIsEnabled(false)
- .copyWithSlots(
- ImmutableIntArray.of(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW)),
+ .copyWithSlots(ImmutableIntArray.of(CommandButton.SLOT_FORWARD)),
button2
.copyWithIsEnabled(false)
.copyWithSlots(ImmutableIntArray.of(CommandButton.SLOT_OVERFLOW)))