From b34a5b4e5d5e00dd271c74b5220f7c8f4682abf7 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 10 Dec 2024 06:10:35 -0800 Subject: [PATCH] Align logic to ignore disabled and non-custom buttons in custom layout The legacy custom layout doesn't support disabled buttons or buttons with non-custom actions. These are currently filtered out, but in inconsistent ways: - MediaControllerImplBase doesn't filter at all. - DefaultNotificationProvider filters before converting mediaButtonPreferences, PlayerWrapper filters after the conversion. - PlayerWrapper doesn't disable buttons that are unavailable. To ensure it's consistent, we can add these checks to the existing util method in CommandButton and also make sure PlayerWrapper disables unavailable buttons before triggering the util method. This also means we can simplify some of the tests that rely on the mediaButtonPreference to customLayout conversion in MediaController. This change also includes two bug fixes in PlayerWrapper that became evident in the tests: The extras need to be copied to avoid modifying a Bundle instance that be used elsewhere and we need to update the custom layout and potentially the session extras when the available commands change, as they depend on them. PiperOrigin-RevId: 704678404 --- .../media3/session/CommandButton.java | 10 + .../media3/session/MediaSessionImpl.java | 5 +- .../media3/session/PlayerWrapper.java | 37 ++- .../media3/session/CommandButtonTest.java | 131 ++++++---- .../media3/session/ConnectionStateTest.java | 2 +- .../media3/session/MediaControllerTest.java | 237 +++--------------- 6 files changed, 162 insertions(+), 260 deletions(-) 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(); }