mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add utilities to resolve button preferences to display constraints
PiperOrigin-RevId: 705491402
This commit is contained in:
parent
c636d9181b
commit
684273e4e1
@ -18,17 +18,22 @@ package androidx.media3.session;
|
||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Assertions.checkState;
|
||||
import static androidx.media3.session.SessionCommand.COMMAND_CODE_CUSTOM;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.util.NullableType;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import com.google.common.base.Objects;
|
||||
@ -701,6 +706,388 @@ public final class CommandButton {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constraints for displaying a list of {@link CommandButton} instances with utilities to resolve
|
||||
* these constraints for a given list of buttons.
|
||||
*/
|
||||
@UnstableApi
|
||||
public static final class DisplayConstraints {
|
||||
|
||||
/** A builder for {@link DisplayConstraints}. */
|
||||
public static final class Builder {
|
||||
|
||||
private final SparseIntArray maxButtonsPerSlot;
|
||||
private final SparseArray<Player.@NullableType Commands> allowedPlayerCommandsPerSlot;
|
||||
private final SparseArray<@NullableType SessionCommands> allowedSessionCommandsPerSlot;
|
||||
private final SparseBooleanArray areCustomCommandsAllowedPerSlot;
|
||||
private boolean buildCalled;
|
||||
|
||||
/** Creates the builder. */
|
||||
public Builder() {
|
||||
maxButtonsPerSlot = new SparseIntArray();
|
||||
maxButtonsPerSlot.put(SLOT_CENTRAL, 1);
|
||||
maxButtonsPerSlot.put(SLOT_BACK, 1);
|
||||
maxButtonsPerSlot.put(SLOT_FORWARD, 1);
|
||||
maxButtonsPerSlot.put(SLOT_OVERFLOW, Integer.MAX_VALUE);
|
||||
allowedPlayerCommandsPerSlot = new SparseArray<>();
|
||||
allowedSessionCommandsPerSlot = new SparseArray<>();
|
||||
areCustomCommandsAllowedPerSlot = new SparseBooleanArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of buttons that can be displayed in a slot.
|
||||
*
|
||||
* <p>The default values are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #SLOT_CENTRAL}, {@link #SLOT_BACK}, {@link #SLOT_FORWARD}: 1
|
||||
* <li>{@link #SLOT_BACK_SECONDARY}, {@link #SLOT_FORWARD_SECONDARY}: 0
|
||||
* <li>{@link #SLOT_OVERFLOW}: {@link Integer#MAX_VALUE}.
|
||||
* </ul>
|
||||
*
|
||||
* @param slot The {@link Slot}.
|
||||
* @param maxButtons The maximum number of buttons that can be displayed in this slot.
|
||||
* @return This builder.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setMaxButtonsForSlot(@Slot int slot, int maxButtons) {
|
||||
checkArgument(maxButtons >= 0);
|
||||
maxButtonsPerSlot.put(slot, maxButtons);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the allowed {@link Player.Commands} for buttons in the given slot.
|
||||
*
|
||||
* <p>The default value ({@code null}) does not restrict the allowed {@link Player.Commands}.
|
||||
*
|
||||
* @param slot The {@link Slot}.
|
||||
* @param allowedPlayerCommands The allowed {@link Player.Commands} for buttons in this slot,
|
||||
* or null to allow all {@link Player.Commands} .
|
||||
* @return This builder.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setAllowedPlayerCommandsForSlot(
|
||||
@Slot int slot, @Nullable Player.Commands allowedPlayerCommands) {
|
||||
allowedPlayerCommandsPerSlot.put(slot, allowedPlayerCommands);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the allowed non-custom {@link SessionCommands} for buttons in the given slot.
|
||||
*
|
||||
* <p>The default value ({@code null}) does not restrict the allowed {@link SessionCommands}.
|
||||
*
|
||||
* <p>This setting has no effect on whether {@linkplain SessionCommand#COMMAND_CODE_CUSTOM
|
||||
* custom session commands} are allowed. Use {@link #setAllowCustomCommandsForSlot} instead.
|
||||
*
|
||||
* @param slot The {@link Slot}.
|
||||
* @param allowedSessionCommands The allowed {@link SessionCommands} for buttons in this slot,
|
||||
* or null to allow all {@link SessionCommands}.
|
||||
* @return This builder.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setAllowedSessionCommandsForSlot(
|
||||
@Slot int slot, @Nullable SessionCommands allowedSessionCommands) {
|
||||
allowedSessionCommandsPerSlot.put(slot, allowedSessionCommands);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether {@linkplain SessionCommand#COMMAND_CODE_CUSTOM custom session commands} are
|
||||
* allowed for buttons in the given slot.
|
||||
*
|
||||
* <p>The default value is {@code true}.
|
||||
*
|
||||
* @param slot The {@link Slot}.
|
||||
* @param allowCustomCommands Whether {@linkplain SessionCommand#COMMAND_CODE_CUSTOM custom
|
||||
* session commands} are allowed for buttons in this slot.
|
||||
* @return This builder.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setAllowCustomCommandsForSlot(@Slot int slot, boolean allowCustomCommands) {
|
||||
areCustomCommandsAllowedPerSlot.put(slot, allowCustomCommands);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds the display constraints. */
|
||||
public DisplayConstraints build() {
|
||||
checkState(!buildCalled);
|
||||
buildCalled = true;
|
||||
return new DisplayConstraints(this);
|
||||
}
|
||||
}
|
||||
|
||||
private final SparseIntArray maxButtonsPerSlot;
|
||||
private final SparseArray<Player.@NullableType Commands> allowedPlayerCommandsPerSlot;
|
||||
private final SparseArray<@NullableType SessionCommands> allowedSessionCommandsPerSlot;
|
||||
private final SparseBooleanArray areCustomCommandsAllowedPerSlot;
|
||||
|
||||
private DisplayConstraints(Builder builder) {
|
||||
this.maxButtonsPerSlot = builder.maxButtonsPerSlot;
|
||||
this.allowedPlayerCommandsPerSlot = builder.allowedPlayerCommandsPerSlot;
|
||||
this.allowedSessionCommandsPerSlot = builder.allowedSessionCommandsPerSlot;
|
||||
this.areCustomCommandsAllowedPerSlot = builder.areCustomCommandsAllowedPerSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a list of {@linkplain MediaController#getMediaButtonPreferences media button
|
||||
* preferences} according to these display constraints and returns the list of buttons to be
|
||||
* displayed.
|
||||
*
|
||||
* <p>Note that the result of this resolution can change whenever the {@code
|
||||
* mediaButtonPreferences} change, or the {@code player} reports any of the following listener
|
||||
* events:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link Player#EVENT_AVAILABLE_COMMANDS_CHANGED}
|
||||
* <li>{@link Player#EVENT_PLAY_WHEN_READY_CHANGED}
|
||||
* <li>{@link Player#EVENT_PLAYBACK_STATE_CHANGED}
|
||||
* <li>{@link Player#EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED}
|
||||
* <li>{@link Player#EVENT_PLAYBACK_STATE_CHANGED}
|
||||
* <li>{@link Player#EVENT_SEEK_BACK_INCREMENT_CHANGED}
|
||||
* <li>{@link Player#EVENT_SEEK_FORWARD_INCREMENT_CHANGED}
|
||||
* </ul>
|
||||
*
|
||||
* @param mediaButtonPreferences The list of {@linkplain
|
||||
* MediaController#getMediaButtonPreferences media button preferences}.
|
||||
* @param player The {@link Player} used to determine default buttons for empty slots.
|
||||
* @return The resolved list of {@linkplain CommandButton buttons} to be displayed. Each button
|
||||
* will have a single {@linkplain CommandButton#slots slot} defined.
|
||||
*/
|
||||
public ImmutableList<CommandButton> resolve(
|
||||
List<CommandButton> mediaButtonPreferences, Player player) {
|
||||
SparseIntArray availableButtonsPerSlot = maxButtonsPerSlot.clone();
|
||||
ImmutableList.Builder<CommandButton> resolvedButtons = ImmutableList.builder();
|
||||
@Nullable CommandButton firstBackButton = null;
|
||||
@Nullable CommandButton firstForwardButton = null;
|
||||
for (int i = 0; i < mediaButtonPreferences.size(); i++) {
|
||||
CommandButton button = mediaButtonPreferences.get(i);
|
||||
for (int j = 0; j < button.slots.length(); j++) {
|
||||
@Slot int slot = button.slots.get(j);
|
||||
if (!reserveSlotForButton(button, slot, availableButtonsPerSlot)) {
|
||||
continue;
|
||||
}
|
||||
resolvedButtons.add(button.copyWithSlots(ImmutableIntArray.of(slot)));
|
||||
if (firstForwardButton == null && slot == SLOT_FORWARD) {
|
||||
firstForwardButton = button;
|
||||
} else if (firstBackButton == null && slot == SLOT_BACK) {
|
||||
firstBackButton = button;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Player.Commands availableCommands = player.getAvailableCommands();
|
||||
boolean centralSlotEmpty =
|
||||
maxButtonsPerSlot.get(SLOT_CENTRAL) == availableButtonsPerSlot.get(SLOT_CENTRAL);
|
||||
if (centralSlotEmpty) {
|
||||
CommandButton defaultCentralButton =
|
||||
createButton(
|
||||
Util.shouldShowPlayButton(player) ? ICON_PLAY : ICON_PAUSE,
|
||||
Player.COMMAND_PLAY_PAUSE,
|
||||
availableCommands);
|
||||
if (reserveSlotForButton(defaultCentralButton, SLOT_CENTRAL, availableButtonsPerSlot)) {
|
||||
resolvedButtons.add(defaultCentralButton);
|
||||
}
|
||||
}
|
||||
boolean backSlotEmpty = firstBackButton == null && maxButtonsPerSlot.get(SLOT_BACK) > 0;
|
||||
boolean forwardSlotEmpty =
|
||||
firstForwardButton == null && maxButtonsPerSlot.get(SLOT_FORWARD) > 0;
|
||||
if (backSlotEmpty && forwardSlotEmpty) {
|
||||
@Player.Command
|
||||
int firstAvailableCommand =
|
||||
getFirstAvailableOrFirstCommand(
|
||||
availableCommands,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS,
|
||||
Player.COMMAND_SEEK_TO_NEXT,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_BACK,
|
||||
Player.COMMAND_SEEK_FORWARD);
|
||||
CommandButton button =
|
||||
createButton(
|
||||
getIconForPlayerCommand(firstAvailableCommand, player),
|
||||
firstAvailableCommand,
|
||||
availableCommands);
|
||||
@Slot int buttonSlot = button.slots.get(0);
|
||||
if (reserveSlotForButton(button, buttonSlot, availableButtonsPerSlot)) {
|
||||
resolvedButtons.add(button);
|
||||
}
|
||||
@Slot int oppositeSlot = buttonSlot == SLOT_BACK ? SLOT_FORWARD : SLOT_BACK;
|
||||
CommandButton oppositeButton = createOppositeButton(button, oppositeSlot, player);
|
||||
if (reserveSlotForButton(oppositeButton, oppositeSlot, availableButtonsPerSlot)) {
|
||||
resolvedButtons.add(oppositeButton);
|
||||
}
|
||||
} else if (backSlotEmpty) {
|
||||
CommandButton oppositeButton = createOppositeButton(firstForwardButton, SLOT_BACK, player);
|
||||
if (reserveSlotForButton(oppositeButton, SLOT_BACK, availableButtonsPerSlot)) {
|
||||
resolvedButtons.add(oppositeButton);
|
||||
}
|
||||
} else if (forwardSlotEmpty) {
|
||||
CommandButton oppositeButton = createOppositeButton(firstBackButton, SLOT_FORWARD, player);
|
||||
if (reserveSlotForButton(oppositeButton, SLOT_FORWARD, availableButtonsPerSlot)) {
|
||||
resolvedButtons.add(oppositeButton);
|
||||
}
|
||||
}
|
||||
return resolvedButtons.build();
|
||||
}
|
||||
|
||||
private boolean reserveSlotForButton(
|
||||
CommandButton button, @Slot int slot, SparseIntArray availableButtonsPerSlot) {
|
||||
if (availableButtonsPerSlot.get(slot) == 0) {
|
||||
return false;
|
||||
}
|
||||
boolean canReserveSlot;
|
||||
if (button.playerCommand != Player.COMMAND_INVALID) {
|
||||
@Nullable Player.Commands allowedCommands = allowedPlayerCommandsPerSlot.get(slot);
|
||||
canReserveSlot = allowedCommands == null || allowedCommands.contains(button.playerCommand);
|
||||
} else if (checkNotNull(button.sessionCommand).commandCode == COMMAND_CODE_CUSTOM) {
|
||||
canReserveSlot = areCustomCommandsAllowedPerSlot.get(slot, /* valueIfKeyNotFound= */ true);
|
||||
} else {
|
||||
@Nullable SessionCommands allowedCommands = allowedSessionCommandsPerSlot.get(slot);
|
||||
canReserveSlot = allowedCommands == null || allowedCommands.contains(button.sessionCommand);
|
||||
}
|
||||
if (canReserveSlot) {
|
||||
availableButtonsPerSlot.put(slot, availableButtonsPerSlot.get(slot) - 1);
|
||||
}
|
||||
return canReserveSlot;
|
||||
}
|
||||
|
||||
private static CommandButton createOppositeButton(
|
||||
@Nullable CommandButton button, @Slot int targetSlot, Player player) {
|
||||
Player.Commands availablePlayerCommands = player.getAvailableCommands();
|
||||
@Player.Command
|
||||
int oppositePlayerCommand =
|
||||
getOppositePlayerCommand(button, targetSlot, availablePlayerCommands);
|
||||
@Icon int oppositeIcon = getOppositeIcon(button);
|
||||
if (oppositeIcon == ICON_UNDEFINED) {
|
||||
oppositeIcon = getIconForPlayerCommand(oppositePlayerCommand, player);
|
||||
}
|
||||
return createButton(oppositeIcon, oppositePlayerCommand, availablePlayerCommands);
|
||||
}
|
||||
|
||||
private static CommandButton createButton(
|
||||
@Icon int icon,
|
||||
@Player.Command int playerCommand,
|
||||
Player.Commands availablePlayerCommands) {
|
||||
return new CommandButton.Builder(icon)
|
||||
.setPlayerCommand(playerCommand)
|
||||
.setEnabled(availablePlayerCommands.contains(playerCommand))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static @Player.Command int getFirstAvailableOrFirstCommand(
|
||||
Player.Commands availableCommands, @Player.Command int... commands) {
|
||||
for (int command : commands) {
|
||||
if (availableCommands.contains(command)) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return commands[0];
|
||||
}
|
||||
|
||||
private static @Player.Command int getOppositePlayerCommand(
|
||||
@Nullable CommandButton button,
|
||||
@Slot int targetSlot,
|
||||
Player.Commands availablePlayerCommands) {
|
||||
if (button != null) {
|
||||
switch (button.playerCommand) {
|
||||
case Player.COMMAND_SEEK_TO_PREVIOUS:
|
||||
return Player.COMMAND_SEEK_TO_NEXT;
|
||||
case Player.COMMAND_SEEK_TO_NEXT:
|
||||
return Player.COMMAND_SEEK_TO_PREVIOUS;
|
||||
case Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM:
|
||||
return Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
|
||||
case Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM:
|
||||
return Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
|
||||
case Player.COMMAND_SEEK_BACK:
|
||||
return Player.COMMAND_SEEK_FORWARD;
|
||||
case Player.COMMAND_SEEK_FORWARD:
|
||||
return Player.COMMAND_SEEK_BACK;
|
||||
default:
|
||||
// Fall through.
|
||||
}
|
||||
}
|
||||
if (targetSlot == SLOT_BACK) {
|
||||
return getFirstAvailableOrFirstCommand(
|
||||
availablePlayerCommands,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_BACK);
|
||||
} else {
|
||||
return getFirstAvailableOrFirstCommand(
|
||||
availablePlayerCommands,
|
||||
Player.COMMAND_SEEK_TO_NEXT,
|
||||
Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_FORWARD);
|
||||
}
|
||||
}
|
||||
|
||||
private static @Icon int getOppositeIcon(@Nullable CommandButton button) {
|
||||
if (button == null) {
|
||||
return ICON_UNDEFINED;
|
||||
}
|
||||
switch (button.icon) {
|
||||
case ICON_PREVIOUS:
|
||||
return ICON_NEXT;
|
||||
case ICON_REWIND:
|
||||
return ICON_FAST_FORWARD;
|
||||
case ICON_SKIP_BACK:
|
||||
return ICON_SKIP_FORWARD;
|
||||
case ICON_NEXT:
|
||||
return ICON_PREVIOUS;
|
||||
case ICON_FAST_FORWARD:
|
||||
return ICON_REWIND;
|
||||
case ICON_SKIP_FORWARD:
|
||||
return ICON_SKIP_BACK;
|
||||
default:
|
||||
// Intentionally don't match numbered SKIP_BACK/FORWARD icons to let
|
||||
// getIconForPlayerCommand determine the best matching icon based on actual skip amount.
|
||||
return ICON_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
private static @Icon int getIconForPlayerCommand(
|
||||
@Player.Command int playerCommand, Player player) {
|
||||
switch (playerCommand) {
|
||||
case Player.COMMAND_SEEK_TO_PREVIOUS:
|
||||
case Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM:
|
||||
return ICON_PREVIOUS;
|
||||
case Player.COMMAND_SEEK_TO_NEXT:
|
||||
case Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM:
|
||||
return ICON_NEXT;
|
||||
case Player.COMMAND_SEEK_BACK:
|
||||
long seekBackIncrement = player.getSeekBackIncrement();
|
||||
if (seekBackIncrement >= 2500 && seekBackIncrement < 7500) {
|
||||
return ICON_SKIP_BACK_5;
|
||||
} else if (seekBackIncrement >= 7500 && seekBackIncrement < 12500) {
|
||||
return ICON_SKIP_BACK_10;
|
||||
} else if (seekBackIncrement >= 12500 && seekBackIncrement < 20000) {
|
||||
return ICON_SKIP_BACK_15;
|
||||
} else if (seekBackIncrement >= 20000 && seekBackIncrement < 40000) {
|
||||
return ICON_SKIP_BACK_30;
|
||||
} else {
|
||||
return ICON_SKIP_BACK;
|
||||
}
|
||||
case Player.COMMAND_SEEK_FORWARD:
|
||||
long seekForwardIncrement = player.getSeekForwardIncrement();
|
||||
if (seekForwardIncrement >= 2500 && seekForwardIncrement < 7500) {
|
||||
return ICON_SKIP_FORWARD_5;
|
||||
} else if (seekForwardIncrement >= 7500 && seekForwardIncrement < 12500) {
|
||||
return ICON_SKIP_FORWARD_10;
|
||||
} else if (seekForwardIncrement >= 12500 && seekForwardIncrement < 20000) {
|
||||
return ICON_SKIP_FORWARD_15;
|
||||
} else if (seekForwardIncrement >= 20000 && seekForwardIncrement < 40000) {
|
||||
return ICON_SKIP_FORWARD_30;
|
||||
} else {
|
||||
return ICON_SKIP_FORWARD;
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The session command of the button. Will be {@code null} if {@link #playerCommand} is set. */
|
||||
@Nullable public final SessionCommand sessionCommand;
|
||||
|
||||
@ -1211,7 +1598,7 @@ public final class CommandButton {
|
||||
CommandButton button = mediaButtonPreferences.get(i);
|
||||
if (!button.isEnabled
|
||||
|| button.sessionCommand == null
|
||||
|| button.sessionCommand.commandCode != SessionCommand.COMMAND_CODE_CUSTOM) {
|
||||
|| button.sessionCommand.commandCode != COMMAND_CODE_CUSTOM) {
|
||||
continue;
|
||||
}
|
||||
for (int s = 0; s < button.slots.length(); s++) {
|
||||
@ -1247,7 +1634,7 @@ public final class CommandButton {
|
||||
CommandButton button = mediaButtonPreferences.get(i);
|
||||
if (!button.isEnabled
|
||||
|| button.sessionCommand == null
|
||||
|| button.sessionCommand.commandCode != SessionCommand.COMMAND_CODE_CUSTOM) {
|
||||
|| button.sessionCommand.commandCode != COMMAND_CODE_CUSTOM) {
|
||||
continue;
|
||||
}
|
||||
if (i != backButtonIndex && i != forwardButtonIndex && button.slots.contains(SLOT_OVERFLOW)) {
|
||||
|
@ -20,7 +20,9 @@ import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.SimpleBasePlayer;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.ImmutableIntArray;
|
||||
@ -1246,4 +1248,598 @@ public class CommandButtonTest {
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayConstraintsResolve_withMaxButtonsPerSlot_limitsToDefinedMaximum() {
|
||||
// Define preferences that match, exceed or are below the allowed number of buttons per slot.
|
||||
// Also provide fallback slots to check they are used if the first preference is not available.
|
||||
ImmutableList<CommandButton> mediaButtonPreferences =
|
||||
ImmutableList.of(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_BACK_SECONDARY)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command4", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_BACK, CommandButton.SLOT_BACK_SECONDARY)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command5", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command6", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build());
|
||||
// Including edge cases of 0 and max integer number of slots.
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder()
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_CENTRAL, /* maxButtons= */ 2)
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_FORWARD, /* maxButtons= */ 0)
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_BACK, /* maxButtons= */ 1)
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_BACK_SECONDARY, /* maxButtons= */ 2)
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, /* maxButtons= */ Integer.MAX_VALUE)
|
||||
.build();
|
||||
Player player = createFixedStatePlayer();
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command1", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_OVERFLOW)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command4", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_BACK_SECONDARY)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("command5", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
displayConstraintsResolve_withAllowedSessionCommandsPerSlot_limitsToAllowedCommands() {
|
||||
// Define preferences and constraints with no, single or multiple matches.
|
||||
// Also provide fallback slots to check they are used if the first preference is not available.
|
||||
ImmutableList<CommandButton> mediaButtonPreferences =
|
||||
ImmutableList.of(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(
|
||||
new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_ITEM))
|
||||
.setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_SEARCH))
|
||||
.setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(
|
||||
new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_CHILDREN))
|
||||
.setSlots(CommandButton.SLOT_BACK, CommandButton.SLOT_OVERFLOW)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(
|
||||
new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build());
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder()
|
||||
.setAllowedSessionCommandsForSlot(
|
||||
CommandButton.SLOT_CENTRAL,
|
||||
new SessionCommands.Builder()
|
||||
.add(new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT))
|
||||
.build())
|
||||
.setAllowedSessionCommandsForSlot(
|
||||
CommandButton.SLOT_BACK,
|
||||
new SessionCommands.Builder()
|
||||
.add(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
|
||||
.add(new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_CHILDREN))
|
||||
.build())
|
||||
.setAllowedSessionCommandsForSlot(
|
||||
CommandButton.SLOT_FORWARD,
|
||||
new SessionCommands.Builder()
|
||||
.add(new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_ITEM))
|
||||
.build())
|
||||
.setAllowedSessionCommandsForSlot(CommandButton.SLOT_OVERFLOW, SessionCommands.EMPTY)
|
||||
.build();
|
||||
Player player = createFixedStatePlayer();
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(
|
||||
new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_ITEM))
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(
|
||||
new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayConstraintsResolve_withAllowCustomCommandsPerSlot_limitsToAllowedCommands() {
|
||||
// Define some custom commands, but also a non-custom one to check it's used if custom commands
|
||||
// are not allowed.
|
||||
ImmutableList<CommandButton> mediaButtonPreferences =
|
||||
ImmutableList.of(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("custom1", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("custom2", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("custom3", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_STOP)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build());
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder()
|
||||
// Leave out SLOT_FORWARD to test default value of "true"
|
||||
.setAllowCustomCommandsForSlot(CommandButton.SLOT_BACK, /* allowCustomCommands= */ true)
|
||||
.setAllowCustomCommandsForSlot(
|
||||
CommandButton.SLOT_CENTRAL, /* allowCustomCommands= */ false)
|
||||
.setAllowCustomCommandsForSlot(
|
||||
CommandButton.SLOT_OVERFLOW, /* allowCustomCommands= */ false)
|
||||
.build();
|
||||
Player player = createFixedStatePlayer();
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("custom1", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setSessionCommand(new SessionCommand("custom2", Bundle.EMPTY))
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_STOP)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
displayConstraintsResolve_withAllowedPlayerCommandsPerSlot_limitsToAllowedCustomCommands() {
|
||||
// Define preferences and constraints with no, single or multiple matches.
|
||||
// Also provide fallback slots to check they are used if the first preference is not available.
|
||||
ImmutableList<CommandButton> mediaButtonPreferences =
|
||||
ImmutableList.of(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_PREPARE)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_STOP)
|
||||
.setSlots(CommandButton.SLOT_FORWARD, CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||
.setSlots(CommandButton.SLOT_OVERFLOW, CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_GET_TRACKS)
|
||||
.setSlots(CommandButton.SLOT_BACK, CommandButton.SLOT_OVERFLOW)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build());
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder()
|
||||
.setAllowedPlayerCommandsForSlot(
|
||||
CommandButton.SLOT_CENTRAL,
|
||||
new Player.Commands.Builder().add(Player.COMMAND_CHANGE_MEDIA_ITEMS).build())
|
||||
.setAllowedPlayerCommandsForSlot(
|
||||
CommandButton.SLOT_BACK,
|
||||
new Player.Commands.Builder()
|
||||
.addAll(Player.COMMAND_PREPARE, Player.COMMAND_GET_TRACKS)
|
||||
.build())
|
||||
.setAllowedPlayerCommandsForSlot(
|
||||
CommandButton.SLOT_FORWARD,
|
||||
new Player.Commands.Builder().add(Player.COMMAND_STOP).build())
|
||||
.setAllowedPlayerCommandsForSlot(CommandButton.SLOT_OVERFLOW, Player.Commands.EMPTY)
|
||||
.build();
|
||||
Player player = createFixedStatePlayer();
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_PREPARE)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_STOP)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayConstraintsResolve_defaultConstraintsNoPreferences_createsDefaultButtons() {
|
||||
ImmutableList<CommandButton> mediaButtonPreferences = ImmutableList.of();
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder().build();
|
||||
// Allow multiple forward/back operations to check the preferred one is used.
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ new Player.Commands.Builder()
|
||||
.addAll(
|
||||
Player.COMMAND_PLAY_PAUSE,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_BACK,
|
||||
Player.COMMAND_SEEK_FORWARD)
|
||||
.build(),
|
||||
/* playWhenReady= */ true,
|
||||
/* playbackState= */ Player.STATE_READY);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_PAUSE)
|
||||
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_PREVIOUS)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_NEXT)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
displayConstraintsResolve_defaultConstraintsNoPreferencesWithoutAvailableCommands_createsDisabledDefaultButtons() {
|
||||
ImmutableList<CommandButton> mediaButtonPreferences = ImmutableList.of();
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder().build();
|
||||
// Add a single available command to test the combination of available/unavailable seek actions.
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ new Player.Commands.Builder()
|
||||
.add(Player.COMMAND_SEEK_TO_NEXT)
|
||||
.build(),
|
||||
/* playWhenReady= */ false,
|
||||
/* playbackState= */ Player.STATE_READY);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_PLAY)
|
||||
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.setEnabled(false)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_NEXT)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_PREVIOUS)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.setEnabled(false)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayConstraintsResolve_noSpaceForDefaultButtons_createsNoDefaultButtons() {
|
||||
// Block slots by a mix of button preferences and setting max buttons to zero.
|
||||
ImmutableList<CommandButton> mediaButtonPreferences =
|
||||
ImmutableList.of(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_SET_SPEED_AND_PITCH)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build());
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder()
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_CENTRAL, /* maxButtons= */ 0)
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_BACK, /* maxButtons= */ 0)
|
||||
.build();
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ new Player.Commands.Builder()
|
||||
.addAll(
|
||||
Player.COMMAND_PLAY_PAUSE,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS,
|
||||
Player.COMMAND_SEEK_TO_NEXT)
|
||||
.build(),
|
||||
/* playWhenReady= */ true,
|
||||
/* playbackState= */ Player.STATE_READY);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_ALBUM)
|
||||
.setPlayerCommand(Player.COMMAND_SET_SPEED_AND_PITCH)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
displayConstraintsResolve_onlySpaceForDefaultForwardButton_createsDefaultForwardButton() {
|
||||
ImmutableList<CommandButton> mediaButtonPreferences = ImmutableList.of();
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder()
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_CENTRAL, /* maxButtons= */ 0)
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_BACK, /* maxButtons= */ 0)
|
||||
.build();
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ new Player.Commands.Builder()
|
||||
.addAll(
|
||||
Player.COMMAND_PLAY_PAUSE,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS,
|
||||
Player.COMMAND_SEEK_TO_NEXT)
|
||||
.build(),
|
||||
/* playWhenReady= */ true,
|
||||
/* playbackState= */ Player.STATE_READY);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_NEXT)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayConstraintsResolve_onlySpaceForDefaultBackButton_createsDefaultBackButton() {
|
||||
ImmutableList<CommandButton> mediaButtonPreferences = ImmutableList.of();
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder()
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_CENTRAL, /* maxButtons= */ 0)
|
||||
.setMaxButtonsForSlot(CommandButton.SLOT_FORWARD, /* maxButtons= */ 0)
|
||||
.build();
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ Player.Commands.EMPTY,
|
||||
/* playWhenReady= */ true,
|
||||
/* playbackState= */ Player.STATE_READY);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_PREVIOUS)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.setEnabled(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
displayConstraintsResolve_defaultConstraintsNoPreferencesWithBackForwardCommands_createsDefaultButtonsWithMatchingIncrement() {
|
||||
ImmutableList<CommandButton> mediaButtonPreferences = ImmutableList.of();
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder().build();
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ new Player.Commands.Builder()
|
||||
.addAll(
|
||||
Player.COMMAND_PLAY_PAUSE,
|
||||
Player.COMMAND_SEEK_BACK,
|
||||
Player.COMMAND_SEEK_FORWARD)
|
||||
.build(),
|
||||
/* playWhenReady= */ true,
|
||||
/* playbackState= */ Player.STATE_READY,
|
||||
/* seekBackIncrementMs= */ 5500,
|
||||
/* seekForwardIncrementMs= */ 14000);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_PAUSE)
|
||||
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_SKIP_BACK_5)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_BACK)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_FORWARD)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
displayConstraintsResolve_withForwardButtonPreference_createsMatchingDefaultBackButton() {
|
||||
ImmutableList<CommandButton> mediaButtonPreferences =
|
||||
ImmutableList.of(
|
||||
new CommandButton.Builder(CommandButton.ICON_FAST_FORWARD)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build());
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder().build();
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ new Player.Commands.Builder()
|
||||
.addAll(
|
||||
Player.COMMAND_PLAY_PAUSE,
|
||||
Player.COMMAND_SEEK_TO_NEXT,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS,
|
||||
Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
|
||||
.build(),
|
||||
/* playWhenReady= */ true,
|
||||
/* playbackState= */ Player.STATE_READY);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_FAST_FORWARD)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_PAUSE)
|
||||
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_REWIND)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
displayConstraintsResolve_withBackButtonPreference_createsMatchingDefaultForwardButton() {
|
||||
ImmutableList<CommandButton> mediaButtonPreferences =
|
||||
ImmutableList.of(
|
||||
new CommandButton.Builder(CommandButton.ICON_SKIP_BACK)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build());
|
||||
CommandButton.DisplayConstraints displayConstraints =
|
||||
new CommandButton.DisplayConstraints.Builder().build();
|
||||
Player player =
|
||||
createFixedStatePlayer(
|
||||
/* availableCommands= */ new Player.Commands.Builder()
|
||||
.addAll(
|
||||
Player.COMMAND_PLAY_PAUSE,
|
||||
Player.COMMAND_SEEK_TO_NEXT,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS,
|
||||
Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
||||
Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
|
||||
.build(),
|
||||
/* playWhenReady= */ true,
|
||||
/* playbackState= */ Player.STATE_READY);
|
||||
|
||||
ImmutableList<CommandButton> resolvedButtons =
|
||||
displayConstraints.resolve(mediaButtonPreferences, player);
|
||||
|
||||
assertThat(resolvedButtons)
|
||||
.containsExactly(
|
||||
new CommandButton.Builder(CommandButton.ICON_SKIP_BACK)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||
.setSlots(CommandButton.SLOT_BACK)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_PAUSE)
|
||||
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||
.setSlots(CommandButton.SLOT_CENTRAL)
|
||||
.build(),
|
||||
new CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
|
||||
.setSlots(CommandButton.SLOT_FORWARD)
|
||||
.build())
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
private static Player createFixedStatePlayer() {
|
||||
return createFixedStatePlayer(
|
||||
/* availableCommands= */ Player.Commands.EMPTY,
|
||||
/* playWhenReady= */ false,
|
||||
/* playbackState= */ Player.STATE_IDLE);
|
||||
}
|
||||
|
||||
private static Player createFixedStatePlayer(
|
||||
Player.Commands availableCommands, boolean playWhenReady, @Player.State int playbackState) {
|
||||
return createFixedStatePlayer(
|
||||
availableCommands,
|
||||
playWhenReady,
|
||||
playbackState,
|
||||
/* seekBackIncrementMs= */ 5500,
|
||||
/* seekForwardIncrementMs= */ 14000);
|
||||
}
|
||||
|
||||
private static Player createFixedStatePlayer(
|
||||
Player.Commands availableCommands,
|
||||
boolean playWhenReady,
|
||||
@Player.State int playbackState,
|
||||
long seekBackIncrementMs,
|
||||
long seekForwardIncrementMs) {
|
||||
return new SimpleBasePlayer(Looper.myLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return new State.Builder()
|
||||
.setAvailableCommands(availableCommands)
|
||||
.setPlayWhenReady(playWhenReady, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
|
||||
.setPlaybackState(playbackState)
|
||||
.setPlaylist(ImmutableList.of(new MediaItemData.Builder("uid").build()))
|
||||
.setSeekBackIncrementMs(seekBackIncrementMs)
|
||||
.setSeekForwardIncrementMs(seekForwardIncrementMs)
|
||||
.build();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user