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 8c1ab8256c..4fcb7940ee 100644 --- a/libraries/session/src/main/java/androidx/media3/session/CommandButton.java +++ b/libraries/session/src/main/java/androidx/media3/session/CommandButton.java @@ -1179,17 +1179,17 @@ public final class CommandButton { * custom layout} according to the implicit button placement rules applied for custom layouts. * * @param mediaButtonPreferences The list of buttons as media button preferences. - * @param reservationExtras A writable {@link Bundle} that receives the extras for slot - * reservations via {@link MediaConstants#EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT} or {@link - * MediaConstants#EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV} to match the returned custom - * layout. - * @return A list of buttons compatible with the placement rules of custom layouts. + * @param backSlotAllowed Whether the custom layout can put a button into {@link #SLOT_BACK}. + * @param forwardSlotAllowed Whether the custom layout can put a button into {@link + * #SLOT_FORWARD}. + * @return A list of buttons compatible with the placement rules of custom layouts. The buttons + * will have their intended slots assigned as the only option. */ /* package */ static ImmutableList getCustomLayoutFromMediaButtonPreferences( - List mediaButtonPreferences, Bundle reservationExtras) { + List mediaButtonPreferences, + boolean backSlotAllowed, + boolean forwardSlotAllowed) { if (mediaButtonPreferences.isEmpty()) { - reservationExtras.putBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, true); - reservationExtras.putBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, true); return ImmutableList.of(); } int backButtonIndex = C.INDEX_UNSET; @@ -1201,35 +1201,52 @@ public final class CommandButton { if (slot == SLOT_OVERFLOW) { // Will go into overflow. break; - } else if (backButtonIndex == C.INDEX_UNSET && slot == SLOT_BACK) { + } else if (backSlotAllowed && backButtonIndex == C.INDEX_UNSET && slot == SLOT_BACK) { backButtonIndex = i; - } else if (forwardButtonIndex == C.INDEX_UNSET && slot == SLOT_FORWARD) { + break; + } else if (forwardSlotAllowed + && forwardButtonIndex == C.INDEX_UNSET + && slot == SLOT_FORWARD) { forwardButtonIndex = i; + break; } } } - boolean hasBackButton = backButtonIndex != C.INDEX_UNSET; - boolean hasForwardButton = forwardButtonIndex != C.INDEX_UNSET; - reservationExtras.putBoolean( - MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, !hasBackButton); - reservationExtras.putBoolean( - MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, !hasForwardButton); ImmutableList.Builder customLayout = ImmutableList.builder(); - if (hasBackButton) { - customLayout.add(mediaButtonPreferences.get(backButtonIndex)); + if (backButtonIndex != C.INDEX_UNSET) { + customLayout.add( + mediaButtonPreferences + .get(backButtonIndex) + .copyWithSlots(ImmutableIntArray.of(SLOT_BACK))); } - if (hasForwardButton) { - customLayout.add(mediaButtonPreferences.get(forwardButtonIndex)); + if (forwardButtonIndex != C.INDEX_UNSET) { + customLayout.add( + mediaButtonPreferences + .get(forwardButtonIndex) + .copyWithSlots(ImmutableIntArray.of(SLOT_FORWARD))); } for (int i = 0; i < mediaButtonPreferences.size(); i++) { CommandButton button = mediaButtonPreferences.get(i); if (i != backButtonIndex && i != forwardButtonIndex && button.slots.contains(SLOT_OVERFLOW)) { - customLayout.add(button); + customLayout.add(button.copyWithSlots(ImmutableIntArray.of(SLOT_OVERFLOW))); } } return customLayout.build(); } + /** + * Returns whether the provided list of buttons contains a button for a given {@link Slot}. This + * method assumes the slots have been resolved and there is only a single slot per button. + */ + /* package */ static boolean containsButtonForSlot(List buttons, @Slot int slot) { + for (int i = 0; i < buttons.size(); i++) { + if (buttons.get(i).slots.get(0) == slot) { + return true; + } + } + return false; + } + /** * Converts a list of buttons defined according to the implicit button placement rules for * {@linkplain MediaSession#getCustomLayout custom layouts} to {@linkplain diff --git a/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java b/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java index 756c891cbf..49c408af89 100644 --- a/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java +++ b/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java @@ -131,10 +131,13 @@ import java.util.List; mediaButtonPreferences, CommandButton::toBundle)); } else { // Controller doesn't support media button preferences, send the list as a custom layout. - // Ignore reservation extras as they were not directly supported in older controllers. + // TODO: b/332877990 - Improve this logic to take allowed command and session extras for + // this controller into account instead of assuming all slots are allowed. ImmutableList customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, /* reservationExtras= */ new Bundle()); + mediaButtonPreferences, + /* backSlotAllowed= */ true, + /* forwardSlotAllowed= */ true); bundle.putParcelableArrayList( FIELD_CUSTOM_LAYOUT, BundleCollectionUtil.toBundleArrayList(customLayout, CommandButton::toBundle)); diff --git a/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java b/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java index d4efae6ee2..6a46667874 100644 --- a/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java +++ b/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java @@ -445,14 +445,13 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi Player.Commands playerCommands, ImmutableList mediaButtonPreferences, boolean showPauseButton) { - Bundle reservations = new Bundle(); ImmutableList customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, reservations); + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); boolean hasCustomBackButton = - !reservations.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV); + CommandButton.containsButtonForSlot(customLayout, CommandButton.SLOT_BACK); boolean hasCustomForwardButton = - !reservations.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT); + CommandButton.containsButtonForSlot(customLayout, CommandButton.SLOT_FORWARD); int nextCustomLayoutIndex = 0; ImmutableList.Builder commandButtons = new ImmutableList.Builder<>(); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java index 1a374eb6cc..b170e9d773 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java @@ -2085,10 +2085,13 @@ import java.util.concurrent.ExecutionException; BundleCollectionUtil.toBundleList(mediaButtonPreferences, CommandButton::toBundle)); } else { // Controller doesn't support media button preferences, send the list as a custom layout. - // Ignore reservation extras as they were not directly supported in older controllers. + // TODO: b/332877990 - Improve this logic to take allowed command and session extras for + // this controller into account instead of assuming all slots are allowed. ImmutableList customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, /* reservationExtras= */ new Bundle()); + mediaButtonPreferences, + /* backSlotAllowed= */ true, + /* forwardSlotAllowed= */ true); iController.onSetCustomLayout( sequenceNumber, BundleCollectionUtil.toBundleList(customLayout, CommandButton::toBundle)); 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 e41b6a2332..b1b52906a4 100644 --- a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java +++ b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java @@ -107,9 +107,7 @@ import java.util.List; this.availablePlayerCommands = availablePlayerCommands; this.legacyExtras = legacyExtras; if (!mediaButtonPreferences.isEmpty()) { - this.customLayout = - CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, this.legacyExtras); + updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences(); } } @@ -143,18 +141,16 @@ import java.util.List; this.mediaButtonPreferences = mediaButtonPreferences; boolean hadPrevReservation = legacyExtras.getBoolean( - MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, /* defaultVale= */ false); + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, /* defaultValue= */ false); boolean hadNextReservation = legacyExtras.getBoolean( - MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, /* defaultVale= */ false); - this.customLayout = - CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, legacyExtras); + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, /* defaultValue= */ false); + updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences(); return (legacyExtras.getBoolean( - MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, /* defaultVale= */ false) + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, /* defaultValue= */ false) != hadPrevReservation) || (legacyExtras.getBoolean( - MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, /* defaultVale= */ false) + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, /* defaultValue= */ false) != hadNextReservation); } @@ -169,12 +165,11 @@ 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; if (!mediaButtonPreferences.isEmpty()) { // Re-calculate custom layout in case we have to set any additional extras. - this.customLayout = - CommandButton.getCustomLayoutFromMediaButtonPreferences(mediaButtonPreferences, extras); + updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences(); } - this.legacyExtras = extras; } public Bundle getLegacyExtras() { @@ -1309,6 +1304,18 @@ import java.util.List; checkState(Looper.myLooper() == getApplicationLooper()); } + private void updateCustomLayoutAndLegacyExtrasForMediaButtonPreferences() { + customLayout = + CommandButton.getCustomLayoutFromMediaButtonPreferences( + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); + legacyExtras.putBoolean( + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV, + !CommandButton.containsButtonForSlot(customLayout, CommandButton.SLOT_BACK)); + legacyExtras.putBoolean( + MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT, + !CommandButton.containsButtonForSlot(customLayout, CommandButton.SLOT_FORWARD)); + } + @SuppressWarnings("deprecation") // Uses deprecated PlaybackStateCompat actions. private static long convertCommandToPlaybackStateActions(@Command int command) { switch (command) { 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 50c750930d..210cbe680a 100644 --- a/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java +++ b/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java @@ -560,29 +560,22 @@ public class CommandButtonTest { .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); - Bundle reservationBundle = new Bundle(); ImmutableList customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, reservationBundle); + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_ALBUM) .setPlayerCommand(Player.COMMAND_PREPARE) - .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_BACK) + .setSlots(CommandButton.SLOT_OVERFLOW) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) - .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) + .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV)) - .isTrue(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT)) - .isTrue(); } @Test @@ -605,33 +598,69 @@ public class CommandButtonTest { .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); - Bundle reservationBundle = new Bundle(); ImmutableList customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, reservationBundle); + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_PREVIOUS) .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) - .setSlots(CommandButton.SLOT_BACK, CommandButton.SLOT_OVERFLOW) + .setSlots(CommandButton.SLOT_BACK) .build(), + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_REWIND) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build()) + .inOrder(); + } + + @Test + public void + getCustomLayoutFromMediaButtonPreferences_withBackSlotButNoBackSlotAllowed_returnsCorrectButtons() { + ImmutableList mediaButtonPreferences = + ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) .setPlayerCommand(Player.COMMAND_PREPARE) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_BACK) .build(), + new CommandButton.Builder(CommandButton.ICON_PREVIOUS) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_BACK, CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) + .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) + .build()); + + ImmutableList customLayout = + CommandButton.getCustomLayoutFromMediaButtonPreferences( + mediaButtonPreferences, /* backSlotAllowed= */ false, /* forwardSlotAllowed= */ true); + + assertThat(customLayout) + .containsExactly( + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_PREVIOUS) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_REWIND) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV)) - .isFalse(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT)) - .isTrue(); } @Test @@ -654,33 +683,69 @@ public class CommandButtonTest { .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) .build()); - Bundle reservationBundle = new Bundle(); ImmutableList customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, reservationBundle); + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_NEXT) .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) - .setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW) + .setSlots(CommandButton.SLOT_FORWARD) .build(), + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_REWIND) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build()) + .inOrder(); + } + + @Test + public void + getCustomLayoutFromMediaButtonPreferences_withForwardSlotButNoForwardSlotAllowed_returnsCorrectButtons() { + ImmutableList mediaButtonPreferences = + ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_ALBUM) .setPlayerCommand(Player.COMMAND_PREPARE) .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD) .build(), + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) + .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) + .build()); + + ImmutableList customLayout = + CommandButton.getCustomLayoutFromMediaButtonPreferences( + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ false); + + assertThat(customLayout) + .containsExactly( + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_REWIND) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV)) - .isTrue(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT)) - .isFalse(); } @Test @@ -708,37 +773,77 @@ public class CommandButtonTest { .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) .setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK) .build()); - Bundle reservationBundle = new Bundle(); ImmutableList customLayout = CommandButton.getCustomLayoutFromMediaButtonPreferences( - mediaButtonPreferences, reservationBundle); + mediaButtonPreferences, /* backSlotAllowed= */ true, /* forwardSlotAllowed= */ true); assertThat(customLayout) .containsExactly( new CommandButton.Builder(CommandButton.ICON_PREVIOUS) .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) - .setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK) + .setSlots(CommandButton.SLOT_BACK) + .build(), + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSlots(CommandButton.SLOT_FORWARD) + .build(), + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_REWIND) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build()) + .inOrder(); + } + + @Test + public void + getCustomLayoutFromMediaButtonPreferences_withForwardAndBackSlotButNoForwardBackSlotsAllowed_returnsCorrectButtons() { + ImmutableList mediaButtonPreferences = + ImmutableList.of( + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD) .build(), new CommandButton.Builder(CommandButton.ICON_NEXT) .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) .setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW) .build(), - new CommandButton.Builder(CommandButton.ICON_ALBUM) - .setPlayerCommand(Player.COMMAND_PREPARE) - .setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD) + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSlots(CommandButton.SLOT_FORWARD_SECONDARY) .build(), new CommandButton.Builder(CommandButton.ICON_REWIND) .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) .setSlots(CommandButton.SLOT_BACK_SECONDARY, CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_PREVIOUS) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK) + .build()); + + ImmutableList customLayout = + CommandButton.getCustomLayoutFromMediaButtonPreferences( + mediaButtonPreferences, /* backSlotAllowed= */ false, /* forwardSlotAllowed= */ false); + + assertThat(customLayout) + .containsExactly( + new CommandButton.Builder(CommandButton.ICON_ALBUM) + .setPlayerCommand(Player.COMMAND_PREPARE) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_NEXT) + .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) + .setSlots(CommandButton.SLOT_OVERFLOW) + .build(), + new CommandButton.Builder(CommandButton.ICON_REWIND) + .setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS) + .setSlots(CommandButton.SLOT_OVERFLOW) .build()) .inOrder(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV)) - .isFalse(); - assertThat( - reservationBundle.getBoolean(MediaConstants.EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT)) - .isFalse(); } @Test