diff --git a/libraries/session/src/main/java/androidx/media3/session/CommandButton.java b/libraries/session/src/main/java/androidx/media3/session/CommandButton.java index 70574bbd8c..ea27fda10c 100644 --- a/libraries/session/src/main/java/androidx/media3/session/CommandButton.java +++ b/libraries/session/src/main/java/androidx/media3/session/CommandButton.java @@ -1209,6 +1209,11 @@ public final class CommandButton { int forwardButtonIndex = C.INDEX_UNSET; for (int i = 0; i < mediaButtonPreferences.size(); i++) { CommandButton button = mediaButtonPreferences.get(i); + if (!button.isEnabled + || button.sessionCommand == null + || button.sessionCommand.commandCode != SessionCommand.COMMAND_CODE_CUSTOM) { + continue; + } for (int s = 0; s < button.slots.length(); s++) { @Slot int slot = button.slots.get(s); if (slot == SLOT_OVERFLOW) { @@ -1240,6 +1245,11 @@ public final class CommandButton { } for (int i = 0; i < mediaButtonPreferences.size(); i++) { CommandButton button = mediaButtonPreferences.get(i); + if (!button.isEnabled + || button.sessionCommand == null + || button.sessionCommand.commandCode != SessionCommand.COMMAND_CODE_CUSTOM) { + continue; + } if (i != backButtonIndex && i != forwardButtonIndex && button.slots.contains(SLOT_OVERFLOW)) { customLayout.add(button.copyWithSlots(ImmutableIntArray.of(SLOT_OVERFLOW))); } diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index a8ebabe83f..5982884195 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -1054,7 +1054,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; boolean commandGetTimelineChanged = playerWrapper.getAvailablePlayerCommands().contains(Player.COMMAND_GET_TIMELINE) != playerCommands.contains(Player.COMMAND_GET_TIMELINE); - playerWrapper.setAvailableCommands(sessionCommands, playerCommands); + boolean extrasChanged = playerWrapper.setAvailableCommands(sessionCommands, playerCommands); + if (extrasChanged) { + sessionLegacyStub.getSessionCompat().setExtras(playerWrapper.getLegacyExtras()); + } if (commandGetTimelineChanged) { sessionLegacyStub.updateLegacySessionPlaybackStateAndQueue(playerWrapper); } else { diff --git a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java index b1b52906a4..65539b108b 100644 --- a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java +++ b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java @@ -105,16 +105,40 @@ import java.util.List; this.mediaButtonPreferences = mediaButtonPreferences; this.availableSessionCommands = availableSessionCommands; this.availablePlayerCommands = availablePlayerCommands; - this.legacyExtras = legacyExtras; + this.legacyExtras = new Bundle(legacyExtras); if (!mediaButtonPreferences.isEmpty()) { updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences(); } } - public void setAvailableCommands( + /** + * Sets new available commands for the platform session. + * + * @param availableSessionCommands The {@link SessionCommands}. + * @param availablePlayerCommands The {@link Player.Commands}. + * @return Whether the {@linkplain #getLegacyExtras platform session extras} were updated as a + * result of this change. + */ + public boolean setAvailableCommands( SessionCommands availableSessionCommands, Commands availablePlayerCommands) { this.availableSessionCommands = availableSessionCommands; this.availablePlayerCommands = availablePlayerCommands; + if (mediaButtonPreferences.isEmpty()) { + return false; + } + boolean hadPrevReservation = + legacyExtras.getBoolean( + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, /* defaultValue= */ false); + boolean hadNextReservation = + legacyExtras.getBoolean( + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, /* defaultValue= */ false); + updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences(); + return (legacyExtras.getBoolean( + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, /* defaultValue= */ false) + != hadPrevReservation) + || (legacyExtras.getBoolean( + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, /* defaultValue= */ false) + != hadNextReservation); } public SessionCommands getAvailableSessionCommands() { @@ -165,7 +189,7 @@ import java.util.List; public void setLegacyExtras(Bundle extras) { checkArgument(!extras.containsKey(EXTRAS_KEY_PLAYBACK_SPEED_COMPAT)); checkArgument(!extras.containsKey(EXTRAS_KEY_MEDIA_ID_COMPAT)); - this.legacyExtras = extras; + this.legacyExtras = new Bundle(extras); if (!mediaButtonPreferences.isEmpty()) { // Re-calculate custom layout in case we have to set any additional extras. updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences(); @@ -1305,9 +1329,14 @@ import java.util.List; } private void updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences() { + ImmutableList mediaButtonPreferencesWithUnavailableButtonsDisabled = + CommandButton.copyWithUnavailableButtonsDisabled( + mediaButtonPreferences, availableSessionCommands, availablePlayerCommands); customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); + mediaButtonPreferencesWithUnavailableButtonsDisabled, + /* backSlotAllowed= */ true, + /* forwardSlotAllowed= */ true); legacyExtras.putBoolean( MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, !CommandButton.containsButtonForSlot(customLayout, CommandButton.SLOT_BACK)); diff --git a/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java b/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java index 210cbe680a..410a0fd8cd 100644 --- a/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java +++ b/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java @@ -549,15 +549,15 @@ public class CommandButtonTest { ImmutableList mediaButtonPreferences = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_BACK) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); @@ -568,11 +568,11 @@ public class CommandButtonTest { assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); @@ -583,19 +583,19 @@ public class CommandButtonTest { ImmutableList mediaButtonPreferences = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_BACK) .build(), new CommandButton.Builder(CommandButton.ICON_PREVIOUS) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); @@ -606,15 +606,15 @@ public class CommandButtonTest { assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_PREVIOUS) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK) .build(), new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); @@ -626,19 +626,19 @@ public class CommandButtonTest { ImmutableList mediaButtonPreferences = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_BACK) .build(), new CommandButton.Builder(CommandButton.ICON_PREVIOUS) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); @@ -649,15 +649,15 @@ public class CommandButtonTest { assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_PREVIOUS) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); @@ -668,19 +668,19 @@ public class CommandButtonTest { ImmutableList mediaButtonPreferences = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); @@ -691,15 +691,15 @@ public class CommandButtonTest { assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build(), new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); @@ -711,19 +711,19 @@ public class CommandButtonTest { ImmutableList mediaButtonPreferences = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); @@ -734,15 +734,15 @@ public class CommandButtonTest { assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); @@ -754,23 +754,23 @@ public class CommandButtonTest { ImmutableList mediaButtonPreferences = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_PREVIOUS) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action5", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK) .build()); @@ -781,19 +781,19 @@ public class CommandButtonTest { assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_PREVIOUS) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action5", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build(), new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); @@ -805,23 +805,23 @@ public class CommandButtonTest { ImmutableList mediaButtonPreferences = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action3", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_PREVIOUS) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action5", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK) .build()); @@ -832,20 +832,51 @@ public class CommandButtonTest { assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) - .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) - .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSessionCommand(new SessionCommand("action4", Bundle.EMPTY)) .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); } + @Test + public void + getCustomLayoutFromMediaButtonPreferences_disabledAndNonCustomCommands_returnsCorrectButtons() { + ImmutableList mediaButtonPreferences = + ImmutableList.of( + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_BLOCK) + .setSessionCommand(new SessionCommand("action2", Bundle.EMPTY)) + .setSlots(CommandButton.SLOT_OVERFLOW) + .setEnabled(false) + .build()); + + ImmutableList customLayout = + CommandButton.getCustomLayoutFromMediaButtonPreferences( + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); + + assertThat(customLayout) + .containsExactly( + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setSessionCommand(new SessionCommand("action1", Bundle.EMPTY)) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build()); + } + @Test public void getMediaButtonPreferencesFromCustomLayout_withPrevAndNextCommands_returnsCorrectSlots() { diff --git a/libraries/session/src/test/java/androidx/media3/session/ConnectionStateTest.java b/libraries/session/src/test/java/androidx/media3/session/ConnectionStateTest.java index 29fa2ed207..356dd4c515 100644 --- a/libraries/session/src/test/java/androidx/media3/session/ConnectionStateTest.java +++ b/libraries/session/src/test/java/androidx/media3/session/ConnectionStateTest.java @@ -116,7 +116,7 @@ public class ConnectionStateTest { /* customLayout= */ ImmutableList.of(), /* mediaButtonPreferences= */ ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_HEART_FILLED) - .setPlayerCommand(Player.COMMAND_PREPARE) + .setSessionCommand(new SessionCommand("action", Bundle.EMPTY)) .build()), /* commandButtonsForMediaItems= */ ImmutableList.of(), SessionCommands.EMPTY, 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 c30018093d..1b732ba407 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 @@ -1037,13 +1037,7 @@ public class MediaControllerTest { 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(); + .containsExactly(button1); session.cleanUp(); } @@ -1062,36 +1056,10 @@ public class MediaControllerTest { 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)); + setupMediaButtonPreferences(session, ImmutableList.of(button1, button2)); CountDownLatch latch = new CountDownLatch(2); AtomicReference> reportedCustomLayout = new AtomicReference<>(); AtomicReference> reportedCustomLayoutChanged = new AtomicReference<>(); @@ -1117,30 +1085,16 @@ public class MediaControllerTest { }); ImmutableList initialCustomLayoutFromGetter = threadTestRule.getHandler().postAndSync(controller::getCustomLayout); - session.setMediaButtonPreferences( - ImmutableList.of(button1, button2, button4, button5, button6)); + session.setMediaButtonPreferences(ImmutableList.of(button1)); 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(); + assertThat(initialCustomLayoutFromGetter).containsExactly(button1, button2).inOrder(); + assertThat(newCustomLayoutFromGetter).containsExactly(button1); + assertThat(reportedCustomLayout.get()).containsExactly(button1); + assertThat(reportedCustomLayoutChanged.get()).containsExactly(button1); session.cleanUp(); } @@ -1158,24 +1112,10 @@ public class MediaControllerTest { 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)); + setupMediaButtonPreferences(session, ImmutableList.of(button1, button2)); CountDownLatch latch = new CountDownLatch(2); List> reportedCustomLayoutChanged = new ArrayList<>(); List> getterCustomLayoutChanged = new ArrayList<>(); @@ -1197,103 +1137,18 @@ public class MediaControllerTest { // Remove commands in custom layout from available commands. session.setAvailableCommands(SessionCommands.EMPTY, Player.Commands.EMPTY); - // Add one session and player command back. + // Add one session command back. session.setAvailableCommands( - new SessionCommands.Builder().add(button2.sessionCommand).build(), - new Player.Commands.Builder().add(Player.COMMAND_GET_TRACKS).build()); + new SessionCommands.Builder().add(button2.sessionCommand).build(), Player.Commands.EMPTY); 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(initialCustomLayout).containsExactly(button1, button2); 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(reportedCustomLayoutChanged.get(0)).isEmpty(); + assertThat(reportedCustomLayoutChanged.get(1)).containsExactly(button2); 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))); + assertThat(getterCustomLayoutChanged.get(0)).isEmpty(); + assertThat(getterCustomLayoutChanged.get(1)).containsExactly(button2); session.cleanUp(); } @@ -1309,27 +1164,20 @@ public class MediaControllerTest { .setIconResId(R.drawable.media3_notification_small_icon) .setSessionCommand(new SessionCommand("command1", Bundle.EMPTY)) .build(); + CommandButton buttonIgnored = + new CommandButton.Builder(CommandButton.ICON_UNDEFINED) + .setDisplayName("button2") + .setIconResId(R.drawable.media3_notification_small_icon) + .setPlayerCommand(Player.COMMAND_PLAY_PAUSE) + .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); + CountDownLatch latch = new CountDownLatch(3); List> reportedCustomLayout = new ArrayList<>(); List> getterCustomLayout = new ArrayList<>(); List> reportedCustomLayoutChanged = new ArrayList<>(); @@ -1359,38 +1207,17 @@ public class MediaControllerTest { 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)); + session.setMediaButtonPreferences(ImmutableList.of(button1, buttonIgnored, button2)); + session.setMediaButtonPreferences(ImmutableList.of(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(initialCustomLayout).containsExactly(button1, button2).inOrder(); assertThat(reportedCustomLayout) - .containsExactly( - ImmutableList.of(button1Enabled, button2Disabled), - ImmutableList.of(button3Disabled, button4Disabled), - ImmutableList.of(button1Enabled, button2Disabled)) - .inOrder(); + .containsExactly(ImmutableList.of(button1, button2), ImmutableList.of(button2)); 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(); + .containsExactly(ImmutableList.of(button1, button2), ImmutableList.of(button2)); + assertThat(reportedCustomLayoutChanged).containsExactly(ImmutableList.of(button2)); + assertThat(getterCustomLayoutChanged).containsExactly(ImmutableList.of(button2)); session.cleanUp(); } @@ -1456,7 +1283,8 @@ public class MediaControllerTest { withBackSlot(button2), withForwardSlot(button1), withOverflowSlot(button3)), ImmutableList.of(withBackSlot(button2), withOverflowSlot(button3)), ImmutableList.of(withForwardSlot(button1), withOverflowSlot(button3)), - ImmutableList.of(withOverflowSlot(button3))); + ImmutableList.of(withOverflowSlot(button3))) + .inOrder(); session.cleanUp(); } @@ -1526,7 +1354,8 @@ public class MediaControllerTest { withBackSlot(button2), withForwardSlot(button1), withOverflowSlot(button3)), ImmutableList.of(withBackSlot(button2), withOverflowSlot(button3)), ImmutableList.of(withForwardSlot(button1), withOverflowSlot(button3)), - ImmutableList.of(withOverflowSlot(button3))); + ImmutableList.of(withOverflowSlot(button3))) + .inOrder(); session.cleanUp(); }