diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index e4610387ad..024fcdc796 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -58,6 +58,9 @@
* Fix issue where the current position jumps back when the controller
replaces the current item
([#951](https://github.com/androidx/media/issues/951)).
+ * Change default of `CommandButton.enabled` to `true` and ensure the value
+ can stay false for controllers even if the associated command is
+ available.
* UI:
* Fallback to include audio track language name if `Locale` cannot
identify a display name
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 7179d1dbc8..e173565de6 100644
--- a/libraries/session/src/main/java/androidx/media3/session/CommandButton.java
+++ b/libraries/session/src/main/java/androidx/media3/session/CommandButton.java
@@ -412,6 +412,7 @@ public final class CommandButton implements Bundleable {
extras = Bundle.EMPTY;
playerCommand = Player.COMMAND_INVALID;
icon = ICON_UNDEFINED;
+ enabled = true;
}
/**
@@ -507,6 +508,12 @@ public final class CommandButton implements Bundleable {
/**
* Sets whether the button is enabled.
*
+ *
Note that this value will be set to {@code false} for {@link MediaController} instances if
+ * the corresponding command is not available to this controller (see {@link #setPlayerCommand}
+ * and {@link #setSessionCommand}).
+ *
+ *
The default value is {@code true}.
+ *
* @param enabled Whether the button is enabled.
* @return This builder for chaining.
*/
@@ -571,7 +578,13 @@ public final class CommandButton implements Bundleable {
*/
@UnstableApi public final Bundle extras;
- /** Whether it's enabled. */
+ /**
+ * Whether the button is enabled.
+ *
+ *
Note that this value will be set to {@code false} for {@link MediaController} instances if
+ * the corresponding command is not available to this controller (see {@link #playerCommand} and
+ * {@link #sessionCommand}).
+ */
public final boolean isEnabled;
private CommandButton(
@@ -639,31 +652,35 @@ public final class CommandButton implements Bundleable {
}
/**
- * Returns a list of command buttons with the {@link CommandButton#isEnabled} flag set according
- * to the available commands passed in.
+ * Returns a list of command buttons with the {@link CommandButton#isEnabled} flag set to false if
+ * the corresponding command is not available.
*/
- /* package */ static ImmutableList getEnabledCommandButtons(
+ /* package */ static ImmutableList copyWithUnavailableButtonsDisabled(
List commandButtons,
SessionCommands sessionCommands,
Player.Commands playerCommands) {
- ImmutableList.Builder enabledButtons = new ImmutableList.Builder<>();
+ ImmutableList.Builder updatedButtons = new ImmutableList.Builder<>();
for (int i = 0; i < commandButtons.size(); i++) {
CommandButton button = commandButtons.get(i);
- enabledButtons.add(
- button.copyWithIsEnabled(isEnabled(button, sessionCommands, playerCommands)));
+ if (isButtonCommandAvailable(button, sessionCommands, playerCommands)) {
+ updatedButtons.add(button);
+ } else {
+ updatedButtons.add(button.copyWithIsEnabled(false));
+ }
}
- return enabledButtons.build();
+ return updatedButtons.build();
}
/**
- * Returns whether the {@link CommandButton} is enabled given the available commands passed in.
+ * Returns whether the required command ({@link #playerCommand} or {@link #sessionCommand}) for
+ * the button is available.
*
* @param button The command button.
* @param sessionCommands The available session commands.
* @param playerCommands The available player commands.
- * @return Whether the button is enabled given the available commands.
+ * @return Whether the command required for this button is available.
*/
- /* package */ static boolean isEnabled(
+ /* package */ static boolean isButtonCommandAvailable(
CommandButton button, SessionCommands sessionCommands, Player.Commands playerCommands) {
return (button.sessionCommand != null && sessionCommands.contains(button.sessionCommand))
|| (button.playerCommand != Player.COMMAND_INVALID
@@ -706,7 +723,7 @@ public final class CommandButton implements Bundleable {
if (iconUri != null) {
bundle.putParcelable(FIELD_ICON_URI, iconUri);
}
- if (isEnabled) {
+ if (!isEnabled) {
bundle.putBoolean(FIELD_ENABLED, isEnabled);
}
return bundle;
@@ -722,9 +739,18 @@ public final class CommandButton implements Bundleable {
@SuppressWarnings("deprecation") // Deprecated instance of deprecated class
public static final Creator CREATOR = CommandButton::fromBundle;
- /** Restores a {@code CommandButton} from a {@link Bundle}. */
+ /**
+ * @deprecated Use {@link #fromBundle(Bundle, int)} instead.
+ */
+ @Deprecated
@UnstableApi
public static CommandButton fromBundle(Bundle bundle) {
+ return fromBundle(bundle, MediaSessionStub.VERSION_INT);
+ }
+
+ /** Restores a {@code CommandButton} from a {@link Bundle}. */
+ @UnstableApi
+ public static CommandButton fromBundle(Bundle bundle, int sessionInterfaceVersion) {
@Nullable Bundle sessionCommandBundle = bundle.getBundle(FIELD_SESSION_COMMAND);
@Nullable
SessionCommand sessionCommand =
@@ -735,7 +761,10 @@ public final class CommandButton implements Bundleable {
int iconResId = bundle.getInt(FIELD_ICON_RES_ID, /* defaultValue= */ 0);
CharSequence displayName = bundle.getCharSequence(FIELD_DISPLAY_NAME, /* defaultValue= */ "");
@Nullable Bundle extras = bundle.getBundle(FIELD_EXTRAS);
- boolean enabled = bundle.getBoolean(FIELD_ENABLED, /* defaultValue= */ false);
+ // Before sessionInterfaceVersion == 3, the session expected this value to be meaningless and we
+ // can only assume it was meant to be true.
+ boolean enabled =
+ sessionInterfaceVersion < 3 || bundle.getBoolean(FIELD_ENABLED, /* defaultValue= */ true);
@Nullable Uri iconUri = bundle.getParcelable(FIELD_ICON_URI);
@Icon int icon = bundle.getInt(FIELD_ICON, /* defaultValue= */ ICON_UNDEFINED);
Builder builder = new Builder();
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 b1f0e82a5c..b138ef5319 100644
--- a/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java
+++ b/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java
@@ -164,7 +164,8 @@ import java.util.List;
List commandButtonArrayList = bundle.getParcelableArrayList(FIELD_CUSTOM_LAYOUT);
ImmutableList customLayout =
commandButtonArrayList != null
- ? BundleCollectionUtil.fromBundleList(CommandButton::fromBundle, commandButtonArrayList)
+ ? BundleCollectionUtil.fromBundleList(
+ b -> CommandButton.fromBundle(b, sessionInterfaceVersion), commandButtonArrayList)
: ImmutableList.of();
@Nullable Bundle sessionCommandsBundle = bundle.getBundle(FIELD_SESSION_COMMANDS);
SessionCommands sessionCommands =
diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaController.java b/libraries/session/src/main/java/androidx/media3/session/MediaController.java
index 4961d0a2c8..7b09c3d223 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaController.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaController.java
@@ -388,6 +388,9 @@ public class MediaController implements Player {
* changes the available commands} for a controller that affect whether buttons of the custom
* layout are enabled or disabled.
*
+ * Note that the {@linkplain CommandButton#isEnabled enabled} flag is set to {@code false} if
+ * the available commands do not allow to use a button.
+ *
* @param controller The controller.
* @param layout The ordered list of {@linkplain CommandButton command buttons}.
*/
@@ -976,6 +979,9 @@ public class MediaController implements Player {
*
After being connected, a change of the custom layout is reported with {@link
* Listener#onCustomLayoutChanged(MediaController, List)}.
*
+ *
Note that the {@linkplain CommandButton#isEnabled enabled} flag is set to {@code false} if
+ * the available commands do not allow to use a button.
+ *
* @return The custom layout.
*/
@UnstableApi
diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
index 9e590dbe61..a19de8d34e 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
@@ -120,7 +120,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
private boolean released;
private PlayerInfo playerInfo;
@Nullable private PendingIntent sessionActivity;
- private ImmutableList customLayout;
+ private ImmutableList customLayoutOriginal;
+ private ImmutableList customLayoutWithUnavailableButtonsDisabled;
private SessionCommands sessionCommands;
private Commands playerCommandsFromSession;
private Commands playerCommandsFromPlayer;
@@ -146,7 +147,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
playerInfo = PlayerInfo.DEFAULT;
surfaceSize = Size.UNKNOWN;
sessionCommands = SessionCommands.EMPTY;
- customLayout = ImmutableList.of();
+ customLayoutOriginal = ImmutableList.of();
+ customLayoutWithUnavailableButtonsDisabled = ImmutableList.of();
playerCommandsFromSession = Commands.EMPTY;
playerCommandsFromPlayer = Commands.EMPTY;
intersectedPlayerCommands =
@@ -726,7 +728,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
@Override
public ImmutableList getCustomLayout() {
- return customLayout;
+ return customLayoutWithUnavailableButtonsDisabled;
}
@Override
@@ -2611,8 +2613,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
intersectedPlayerCommands =
createIntersectedCommandsEnsuringCommandReleaseAvailable(
playerCommandsFromSession, playerCommandsFromPlayer);
- customLayout =
- CommandButton.getEnabledCommandButtons(
+ customLayoutOriginal = result.customLayout;
+ customLayoutWithUnavailableButtonsDisabled =
+ CommandButton.copyWithUnavailableButtonsDisabled(
result.customLayout, sessionCommands, intersectedPlayerCommands);
playerInfo = result.playerInfo;
try {
@@ -2765,6 +2768,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
if (!playerCommandsChanged && !sessionCommandsChanged) {
return;
}
+ this.sessionCommands = sessionCommands;
boolean intersectedPlayerCommandsChanged = false;
if (playerCommandsChanged) {
playerCommandsFromSession = playerCommands;
@@ -2776,13 +2780,12 @@ import org.checkerframework.checker.nullness.qual.NonNull;
!Util.areEqual(intersectedPlayerCommands, prevIntersectedPlayerCommands);
}
boolean customLayoutChanged = false;
- if (sessionCommandsChanged) {
- this.sessionCommands = sessionCommands;
- ImmutableList oldCustomLayout = customLayout;
- customLayout =
- CommandButton.getEnabledCommandButtons(
- customLayout, sessionCommands, intersectedPlayerCommands);
- customLayoutChanged = !customLayout.equals(oldCustomLayout);
+ if (sessionCommandsChanged || intersectedPlayerCommandsChanged) {
+ ImmutableList oldCustomLayout = customLayoutWithUnavailableButtonsDisabled;
+ customLayoutWithUnavailableButtonsDisabled =
+ CommandButton.copyWithUnavailableButtonsDisabled(
+ customLayoutOriginal, sessionCommands, intersectedPlayerCommands);
+ customLayoutChanged = !customLayoutWithUnavailableButtonsDisabled.equals(oldCustomLayout);
}
if (intersectedPlayerCommandsChanged) {
listeners.sendEvent(
@@ -2798,7 +2801,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
if (customLayoutChanged) {
getInstance()
.notifyControllerListener(
- listener -> listener.onCustomLayoutChanged(getInstance(), customLayout));
+ listener ->
+ listener.onCustomLayoutChanged(
+ getInstance(), customLayoutWithUnavailableButtonsDisabled));
}
}
@@ -2816,11 +2821,24 @@ import org.checkerframework.checker.nullness.qual.NonNull;
playerCommandsFromSession, playerCommandsFromPlayer);
boolean intersectedPlayerCommandsChanged =
!Util.areEqual(intersectedPlayerCommands, prevIntersectedPlayerCommands);
+ boolean customLayoutChanged = false;
if (intersectedPlayerCommandsChanged) {
+ ImmutableList oldCustomLayout = customLayoutWithUnavailableButtonsDisabled;
+ customLayoutWithUnavailableButtonsDisabled =
+ CommandButton.copyWithUnavailableButtonsDisabled(
+ customLayoutOriginal, sessionCommands, intersectedPlayerCommands);
+ customLayoutChanged = !customLayoutWithUnavailableButtonsDisabled.equals(oldCustomLayout);
listeners.sendEvent(
/* eventFlag= */ Player.EVENT_AVAILABLE_COMMANDS_CHANGED,
listener -> listener.onAvailableCommandsChanged(intersectedPlayerCommands));
}
+ if (customLayoutChanged) {
+ getInstance()
+ .notifyControllerListener(
+ listener ->
+ listener.onCustomLayoutChanged(
+ getInstance(), customLayoutWithUnavailableButtonsDisabled));
+ }
}
// Calling deprecated listener callback method for backwards compatibility.
@@ -2829,19 +2847,24 @@ import org.checkerframework.checker.nullness.qual.NonNull;
if (!isConnected()) {
return;
}
- ImmutableList oldCustomLayout = customLayout;
- customLayout =
- CommandButton.getEnabledCommandButtons(layout, sessionCommands, intersectedPlayerCommands);
- boolean hasCustomLayoutChanged = !Objects.equals(customLayout, oldCustomLayout);
+ ImmutableList oldCustomLayout = customLayoutWithUnavailableButtonsDisabled;
+ customLayoutOriginal = ImmutableList.copyOf(layout);
+ customLayoutWithUnavailableButtonsDisabled =
+ CommandButton.copyWithUnavailableButtonsDisabled(
+ layout, sessionCommands, intersectedPlayerCommands);
+ boolean hasCustomLayoutChanged =
+ !Objects.equals(customLayoutWithUnavailableButtonsDisabled, oldCustomLayout);
getInstance()
.notifyControllerListener(
listener -> {
ListenableFuture future =
checkNotNull(
- listener.onSetCustomLayout(getInstance(), customLayout),
+ listener.onSetCustomLayout(
+ getInstance(), customLayoutWithUnavailableButtonsDisabled),
"MediaController.Listener#onSetCustomLayout() must not return null");
if (hasCustomLayoutChanged) {
- listener.onCustomLayoutChanged(getInstance(), customLayout);
+ listener.onCustomLayoutChanged(
+ getInstance(), customLayoutWithUnavailableButtonsDisabled);
}
sendControllerResultWhenReady(seq, future);
});
diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java
index e382cbd74c..d1245c4ffc 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java
@@ -112,8 +112,18 @@ import org.checkerframework.checker.nullness.qual.NonNull;
}
List layout;
try {
+ @Nullable MediaControllerImplBase controller = this.controller.get();
+ @Nullable
+ SessionToken connectedToken = controller == null ? null : controller.getConnectedToken();
+ if (connectedToken == null) {
+ // Stale event.
+ return;
+ }
+ int sessionInterfaceVersion = connectedToken.getInterfaceVersion();
layout =
- BundleCollectionUtil.fromBundleList(CommandButton::fromBundle, commandButtonBundleList);
+ BundleCollectionUtil.fromBundleList(
+ bundle -> CommandButton.fromBundle(bundle, sessionInterfaceVersion),
+ commandButtonBundleList);
} catch (RuntimeException e) {
Log.w(TAG, "Ignoring malformed Bundle for CommandButton", e);
return;
diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java
index 44f7878ba2..8ec0c33b54 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java
@@ -388,6 +388,9 @@ public class MediaSession {
* Use {@code MediaSession.setCustomLayout(..)} to update the custom layout during the life
* time of the session.
*
+ *
On the controller side, the {@linkplain CommandButton#isEnabled enabled} flag is set to
+ * {@code false} if the available commands of a controller do not allow to use a button.
+ *
* @param customLayout The ordered list of {@link CommandButton command buttons}.
* @return The builder to allow chaining.
*/
@@ -911,7 +914,8 @@ public class MediaSession {
* MediaController#getCustomLayout() controller already has available}. Note that this comparison
* uses {@link CommandButton#equals} and therefore ignores {@link CommandButton#extras}.
*
- *
It's up to controller's decision how to represent the layout in its own UI.
+ *
On the controller side, the {@linkplain CommandButton#isEnabled enabled} flag is set to
+ * {@code false} if the available commands of the controller do not allow to use a button.
*
*
Interoperability: This call has no effect when called for a {@linkplain
* ControllerInfo#LEGACY_CONTROLLER_VERSION legacy controller}.
@@ -933,9 +937,8 @@ public class MediaSession {
*
Calling this method broadcasts the custom layout to all connected Media3 controllers,
* including the {@linkplain #getMediaNotificationControllerInfo() media notification controller}.
*
- *
On the controller side, the {@linkplain CommandButton#isEnabled enabled} flag is set
- * according to the available commands of the controller which overrides a value that has been set
- * by the session.
+ *
On the controller side, the {@linkplain CommandButton#isEnabled enabled} flag is set to
+ * {@code false} if the available commands of a controller do not allow to use a button.
*
*
{@link MediaController.Listener#onCustomLayoutChanged(MediaController, List)} is only called
* if the new custom layout is different to the custom layout the {@linkplain
@@ -1653,7 +1656,9 @@ public class MediaSession {
*
*
Make sure to have the session commands of all command buttons of the custom layout
* included in the {@linkplain #setAvailableSessionCommands(SessionCommands)} available
- * session commands}.
+ * session commands} On the controller side, the {@linkplain CommandButton#isEnabled enabled}
+ * flag is set to {@code false} if the available commands of the controller do not allow to
+ * use a button.
*/
@CanIgnoreReturnValue
public AcceptedResultBuilder setCustomLayout(@Nullable List customLayout) {
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 48c0e2d124..5576ea61a3 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java
@@ -113,7 +113,7 @@ import java.util.concurrent.ExecutionException;
private static final String TAG = "MediaSessionStub";
/** The version of the IMediaSession interface. */
- public static final int VERSION_INT = 2;
+ public static final int VERSION_INT = 3;
/**
* Sequence number used when a controller method is triggered on the sesison side that wasn't
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 f02fe00a9a..cdf97c8265 100644
--- a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java
+++ b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java
@@ -1043,25 +1043,23 @@ import java.util.List;
for (int i = 0; i < customLayout.size(); i++) {
CommandButton commandButton = customLayout.get(i);
- if (commandButton.sessionCommand != null) {
- SessionCommand sessionCommand = commandButton.sessionCommand;
- if (sessionCommand.commandCode == SessionCommand.COMMAND_CODE_CUSTOM
- && CommandButton.isEnabled(
- commandButton, availableSessionCommands, availablePlayerCommands)) {
- Bundle actionExtras = sessionCommand.customExtras;
- if (commandButton.icon != CommandButton.ICON_UNDEFINED) {
- actionExtras = new Bundle(sessionCommand.customExtras);
- actionExtras.putInt(
- MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, commandButton.icon);
- }
- builder.addCustomAction(
- new PlaybackStateCompat.CustomAction.Builder(
- sessionCommand.customAction,
- commandButton.displayName,
- commandButton.iconResId)
- .setExtras(actionExtras)
- .build());
+ SessionCommand sessionCommand = commandButton.sessionCommand;
+ if (sessionCommand != null
+ && commandButton.isEnabled
+ && sessionCommand.commandCode == SessionCommand.COMMAND_CODE_CUSTOM
+ && CommandButton.isButtonCommandAvailable(
+ commandButton, availableSessionCommands, availablePlayerCommands)) {
+ Bundle actionExtras = sessionCommand.customExtras;
+ if (commandButton.icon != CommandButton.ICON_UNDEFINED) {
+ actionExtras = new Bundle(sessionCommand.customExtras);
+ actionExtras.putInt(
+ MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, commandButton.icon);
}
+ builder.addCustomAction(
+ new PlaybackStateCompat.CustomAction.Builder(
+ sessionCommand.customAction, commandButton.displayName, commandButton.iconResId)
+ .setExtras(actionExtras)
+ .build());
}
}
if (playerError != null) {
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 2a74567d40..78c265f2c9 100644
--- a/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java
+++ b/libraries/session/src/test/java/androidx/media3/session/CommandButtonTest.java
@@ -31,7 +31,8 @@ import org.junit.runner.RunWith;
public class CommandButtonTest {
@Test
- public void isEnabled_playerCommandAvailableOrUnavailableInPlayerCommands_isEnabledCorrectly() {
+ public void
+ isButtonCommandAvailable_playerCommandAvailableOrUnavailableInPlayerCommands_isEnabledCorrectly() {
CommandButton button =
new CommandButton.Builder()
.setDisplayName("button")
@@ -41,14 +42,18 @@ public class CommandButtonTest {
Player.Commands availablePlayerCommands =
Player.Commands.EMPTY.buildUpon().add(Player.COMMAND_SEEK_TO_NEXT).build();
- assertThat(CommandButton.isEnabled(button, SessionCommands.EMPTY, Player.Commands.EMPTY))
+ assertThat(
+ CommandButton.isButtonCommandAvailable(
+ button, SessionCommands.EMPTY, Player.Commands.EMPTY))
.isFalse();
- assertThat(CommandButton.isEnabled(button, SessionCommands.EMPTY, availablePlayerCommands))
+ assertThat(
+ CommandButton.isButtonCommandAvailable(
+ button, SessionCommands.EMPTY, availablePlayerCommands))
.isTrue();
}
@Test
- public void isEnabled_sessionCommandAvailableOrUnavailable_isEnabledCorrectly() {
+ public void isButtonCommandAvailable_sessionCommandAvailableOrUnavailable_isEnabledCorrectly() {
SessionCommand command1 = new SessionCommand("command1", Bundle.EMPTY);
CommandButton button =
new CommandButton.Builder()
@@ -59,14 +64,18 @@ public class CommandButtonTest {
SessionCommands availableSessionCommands =
SessionCommands.EMPTY.buildUpon().add(command1).build();
- assertThat(CommandButton.isEnabled(button, SessionCommands.EMPTY, Player.Commands.EMPTY))
+ assertThat(
+ CommandButton.isButtonCommandAvailable(
+ button, SessionCommands.EMPTY, Player.Commands.EMPTY))
.isFalse();
- assertThat(CommandButton.isEnabled(button, availableSessionCommands, Player.Commands.EMPTY))
+ assertThat(
+ CommandButton.isButtonCommandAvailable(
+ button, availableSessionCommands, Player.Commands.EMPTY))
.isTrue();
}
@Test
- public void getEnabledCommandButtons() {
+ public void copyWithUnavailableButtonsDisabled() {
CommandButton button1 =
new CommandButton.Builder()
.setDisplayName("button1")
@@ -86,11 +95,11 @@ public class CommandButtonTest {
Player.Commands.EMPTY.buildUpon().add(Player.COMMAND_SEEK_TO_PREVIOUS).build();
assertThat(
- CommandButton.getEnabledCommandButtons(
+ CommandButton.copyWithUnavailableButtonsDisabled(
ImmutableList.of(button1, button2), SessionCommands.EMPTY, Player.Commands.EMPTY))
- .containsExactly(button1, button2);
+ .containsExactly(button1.copyWithIsEnabled(false), button2.copyWithIsEnabled(false));
assertThat(
- CommandButton.getEnabledCommandButtons(
+ CommandButton.copyWithUnavailableButtonsDisabled(
ImmutableList.of(button1, button2),
availableSessionCommands,
availablePlayerCommands))
@@ -134,7 +143,8 @@ public class CommandButtonTest {
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
.build();
- CommandButton serialisedButton = CommandButton.fromBundle(button.toBundle());
+ CommandButton serialisedButton =
+ CommandButton.fromBundle(button.toBundle(), MediaSessionStub.VERSION_INT);
assertThat(serialisedButton.iconUri).isEqualTo(uri);
}
@@ -148,7 +158,8 @@ public class CommandButtonTest {
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
.build();
- CommandButton serialisedButton = CommandButton.fromBundle(button.toBundle());
+ CommandButton serialisedButton =
+ CommandButton.fromBundle(button.toBundle(), MediaSessionStub.VERSION_INT);
assertThat(serialisedButton.iconUri).isNull();
}
@@ -180,7 +191,8 @@ public class CommandButtonTest {
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
.build();
- assertThat(button).isEqualTo(CommandButton.fromBundle(button.toBundle()));
+ assertThat(button)
+ .isEqualTo(CommandButton.fromBundle(button.toBundle(), MediaSessionStub.VERSION_INT));
assertThat(button)
.isNotEqualTo(
new CommandButton.Builder()
@@ -205,7 +217,7 @@ public class CommandButtonTest {
assertThat(button)
.isNotEqualTo(
new CommandButton.Builder()
- .setEnabled(true)
+ .setEnabled(false)
.setDisplayName("button")
.setIconResId(R.drawable.media3_notification_small_icon)
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
@@ -380,11 +392,11 @@ public class CommandButtonTest {
new CommandButton.Builder().setPlayerCommand(Player.COMMAND_PLAY_PAUSE).build();
CommandButton restoredButtonWithSessionCommand =
- CommandButton.fromBundle(buttonWithSessionCommand.toBundle());
+ CommandButton.fromBundle(buttonWithSessionCommand.toBundle(), MediaSessionStub.VERSION_INT);
CommandButton restoredButtonWithPlayerCommand =
- CommandButton.fromBundle(buttonWithPlayerCommand.toBundle());
+ CommandButton.fromBundle(buttonWithPlayerCommand.toBundle(), MediaSessionStub.VERSION_INT);
CommandButton restoredButtonWithDefaultValues =
- CommandButton.fromBundle(buttonWithDefaultValues.toBundle());
+ CommandButton.fromBundle(buttonWithDefaultValues.toBundle(), MediaSessionStub.VERSION_INT);
assertThat(restoredButtonWithSessionCommand).isEqualTo(buttonWithSessionCommand);
assertThat(restoredButtonWithSessionCommand.extras.get("key")).isEqualTo("value");
@@ -392,4 +404,19 @@ public class CommandButtonTest {
assertThat(restoredButtonWithPlayerCommand.extras.get("key")).isEqualTo("value");
assertThat(restoredButtonWithDefaultValues).isEqualTo(buttonWithDefaultValues);
}
+
+ @Test
+ public void fromBundle_withSessionInterfaceVersionLessThan3_setsEnabledToTrue() {
+ CommandButton buttonWithEnabledFalse =
+ new CommandButton.Builder()
+ .setEnabled(false)
+ .setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
+ .build();
+
+ CommandButton restoredButtonAssumingOldSessionInterface =
+ CommandButton.fromBundle(
+ buttonWithEnabledFalse.toBundle(), /* sessionInterfaceVersion= */ 2);
+
+ assertThat(restoredButtonAssumingOldSessionInterface.isEnabled).isTrue();
+ }
}
diff --git a/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java b/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java
index f6bb52666f..7b84bd1ddd 100644
--- a/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java
+++ b/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java
@@ -158,6 +158,8 @@ public class MediaSessionServiceTest {
throws TimeoutException {
SessionCommand command1 = new SessionCommand("command1", Bundle.EMPTY);
SessionCommand command2 = new SessionCommand("command2", Bundle.EMPTY);
+ SessionCommand command3 = new SessionCommand("command3", Bundle.EMPTY);
+ SessionCommand command4 = new SessionCommand("command4", Bundle.EMPTY);
CommandButton button1 =
new CommandButton.Builder()
.setDisplayName("customAction1")
@@ -170,10 +172,23 @@ public class MediaSessionServiceTest {
.setIconResId(R.drawable.media3_notification_small_icon)
.setSessionCommand(command2)
.build();
+ CommandButton button3 =
+ new CommandButton.Builder()
+ .setDisplayName("customAction3")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(command3)
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder()
+ .setDisplayName("customAction4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setSessionCommand(command4)
+ .build();
ExoPlayer player = new TestExoPlayerBuilder(context).build();
MediaSession session =
new MediaSession.Builder(context, player)
- .setCustomLayout(ImmutableList.of(button1, button2))
+ .setCustomLayout(ImmutableList.of(button1, button2, button3, button4))
.setCallback(
new MediaSession.Callback() {
@Override
@@ -186,6 +201,7 @@ public class MediaSessionServiceTest {
.buildUpon()
.add(command1)
.add(command2)
+ .add(command3)
.build())
.build();
}
diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest.java
index 40897444ab..c17452c1f1 100644
--- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest.java
+++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest.java
@@ -1446,10 +1446,9 @@ public class MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest
Player player = createDefaultPlayer();
Bundle extras1 = new Bundle();
extras1.putString("key1", "value1");
- Bundle extras2 = new Bundle();
- extras1.putString("key2", "value2");
SessionCommand command1 = new SessionCommand("command1", extras1);
- SessionCommand command2 = new SessionCommand("command2", extras2);
+ SessionCommand command2 = new SessionCommand("command2", Bundle.EMPTY);
+ SessionCommand command3 = new SessionCommand("command3", Bundle.EMPTY);
ImmutableList customLayout =
ImmutableList.of(
new CommandButton.Builder()
@@ -1461,6 +1460,12 @@ public class MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest
.setDisplayName("button2")
.setIconResId(R.drawable.media3_notification_pause)
.setSessionCommand(command2)
+ .build(),
+ new CommandButton.Builder()
+ .setDisplayName("button3")
+ .setEnabled(false)
+ .setIconResId(R.drawable.media3_notification_pause)
+ .setSessionCommand(command3)
.build());
MediaSession.Callback callback =
new MediaSession.Callback() {
@@ -1469,7 +1474,11 @@ public class MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest
MediaSession session, MediaSession.ControllerInfo controller) {
return new AcceptedResultBuilder(session)
.setAvailableSessionCommands(
- ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon().add(command1).build())
+ ConnectionResult.DEFAULT_SESSION_COMMANDS
+ .buildUpon()
+ .add(command1)
+ .add(command3)
+ .build())
.build();
}
};
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 8738707fa7..4f8b41ac9d 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
@@ -123,32 +123,31 @@ public class MediaControllerTest {
@Test
public void builder() throws Exception {
- MediaController.Builder builder;
SessionToken token = remoteSession.getToken();
try {
- builder = new MediaController.Builder(null, token);
+ new MediaController.Builder(null, token);
assertWithMessage("null context shouldn't be allowed").fail();
} catch (NullPointerException e) {
// expected. pass-through
}
try {
- builder = new MediaController.Builder(context, null);
+ new MediaController.Builder(context, null);
assertWithMessage("null token shouldn't be allowed").fail();
} catch (NullPointerException e) {
// expected. pass-through
}
try {
- builder = new MediaController.Builder(context, token).setListener(null);
+ new MediaController.Builder(context, token).setListener(null);
assertWithMessage("null listener shouldn't be allowed").fail();
} catch (NullPointerException e) {
// expected. pass-through
}
try {
- builder = new MediaController.Builder(context, token).setApplicationLooper(null);
+ new MediaController.Builder(context, token).setApplicationLooper(null);
assertWithMessage("null looper shouldn't be allowed").fail();
} catch (NullPointerException e) {
// expected. pass-through
@@ -182,6 +181,7 @@ public class MediaControllerTest {
CommandButton button2 =
new CommandButton.Builder()
.setDisplayName("button2")
+ .setEnabled(false)
.setIconResId(R.drawable.media3_notification_small_icon)
.setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
.build();
@@ -191,11 +191,28 @@ public class MediaControllerTest {
.setIconResId(R.drawable.media3_notification_small_icon)
.setSessionCommand(new SessionCommand("command3", Bundle.EMPTY))
.build();
- setupCustomLayout(session, ImmutableList.of(button1, button2, button3));
+ CommandButton button4 =
+ new CommandButton.Builder()
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ CommandButton button5 =
+ new CommandButton.Builder()
+ .setDisplayName("button5")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button2, button3, button4, button5));
MediaController controller = controllerTestRule.createController(session.getToken());
assertThat(threadTestRule.getHandler().postAndSync(controller::getCustomLayout))
- .containsExactly(button1.copyWithIsEnabled(true), button2.copyWithIsEnabled(true), button3)
+ .containsExactly(
+ button1.copyWithIsEnabled(true),
+ button2.copyWithIsEnabled(false),
+ button3.copyWithIsEnabled(false),
+ button4.copyWithIsEnabled(true),
+ button5.copyWithIsEnabled(false))
.inOrder();
session.cleanUp();
@@ -214,6 +231,7 @@ public class MediaControllerTest {
CommandButton button2 =
new CommandButton.Builder()
.setDisplayName("button2")
+ .setEnabled(false)
.setIconResId(R.drawable.media3_notification_small_icon)
.setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
.build();
@@ -229,7 +247,19 @@ public class MediaControllerTest {
.setIconResId(R.drawable.media3_notification_small_icon)
.setSessionCommand(new SessionCommand("command4", Bundle.EMPTY))
.build();
- setupCustomLayout(session, ImmutableList.of(button1, button2));
+ CommandButton button5 =
+ new CommandButton.Builder()
+ .setDisplayName("button5")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ CommandButton button6 =
+ new CommandButton.Builder()
+ .setDisplayName("button6")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button3));
CountDownLatch latch = new CountDownLatch(2);
AtomicReference> reportedCustomLayout = new AtomicReference<>();
AtomicReference> reportedCustomLayoutChanged = new AtomicReference<>();
@@ -255,23 +285,32 @@ public class MediaControllerTest {
});
ImmutableList initialCustomLayoutFromGetter =
threadTestRule.getHandler().postAndSync(controller::getCustomLayout);
- session.setCustomLayout(ImmutableList.of(button3, button4));
+ session.setCustomLayout(ImmutableList.of(button1, button2, button4, button5, button6));
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
ImmutableList newCustomLayoutFromGetter =
threadTestRule.getHandler().postAndSync(controller::getCustomLayout);
assertThat(initialCustomLayoutFromGetter)
- .containsExactly(button1.copyWithIsEnabled(true), button2.copyWithIsEnabled(true))
+ .containsExactly(button1.copyWithIsEnabled(true), button3.copyWithIsEnabled(false))
+ .inOrder();
+ ImmutableList expectedNewButtons =
+ ImmutableList.of(
+ button1.copyWithIsEnabled(true),
+ button2.copyWithIsEnabled(false),
+ button4.copyWithIsEnabled(false),
+ button5.copyWithIsEnabled(true),
+ button6.copyWithIsEnabled(false));
+ assertThat(newCustomLayoutFromGetter).containsExactlyElementsIn(expectedNewButtons).inOrder();
+ assertThat(reportedCustomLayout.get()).containsExactlyElementsIn(expectedNewButtons).inOrder();
+ assertThat(reportedCustomLayoutChanged.get())
+ .containsExactlyElementsIn(expectedNewButtons)
.inOrder();
- assertThat(newCustomLayoutFromGetter).containsExactly(button3, button4).inOrder();
- assertThat(reportedCustomLayout.get()).containsExactly(button3, button4).inOrder();
- assertThat(reportedCustomLayoutChanged.get()).containsExactly(button3, button4).inOrder();
session.cleanUp();
}
@Test
- public void getCustomLayout_setAvailableCommandsAddOrRemoveCommands_reportsCustomLayoutChanged()
+ public void getCustomLayout_setAvailableCommandsOnSession_reportsCustomLayoutChanged()
throws Exception {
RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
CommandButton button1 =
@@ -283,10 +322,23 @@ public class MediaControllerTest {
CommandButton button2 =
new CommandButton.Builder()
.setDisplayName("button2")
+ .setEnabled(false)
.setIconResId(R.drawable.media3_notification_small_icon)
.setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
.build();
- setupCustomLayout(session, ImmutableList.of(button1, button2));
+ CommandButton button3 =
+ new CommandButton.Builder()
+ .setDisplayName("button3")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ CommandButton button4 =
+ new CommandButton.Builder()
+ .setDisplayName("button4")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_GET_TRACKS)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button1, button2, button3, button4));
CountDownLatch latch = new CountDownLatch(2);
List> reportedCustomLayoutChanged = new ArrayList<>();
List> getterCustomLayoutChanged = new ArrayList<>();
@@ -308,23 +360,95 @@ public class MediaControllerTest {
// Remove commands in custom layout from available commands.
session.setAvailableCommands(SessionCommands.EMPTY, Player.Commands.EMPTY);
- // Add one command back.
+ // Add one sesion and player command back.
session.setAvailableCommands(
- new SessionCommands.Builder().add(button2.sessionCommand).build(), Player.Commands.EMPTY);
+ new SessionCommands.Builder().add(button2.sessionCommand).build(),
+ new Player.Commands.Builder().add(Player.COMMAND_GET_TRACKS).build());
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(initialCustomLayout)
- .containsExactly(button1.copyWithIsEnabled(true), button2.copyWithIsEnabled(true));
+ .containsExactly(
+ button1.copyWithIsEnabled(true),
+ button2.copyWithIsEnabled(false),
+ button3.copyWithIsEnabled(true),
+ button4.copyWithIsEnabled(false));
assertThat(reportedCustomLayoutChanged).hasSize(2);
- assertThat(reportedCustomLayoutChanged.get(0)).containsExactly(button1, button2).inOrder();
+ assertThat(reportedCustomLayoutChanged.get(0))
+ .containsExactly(
+ button1.copyWithIsEnabled(false),
+ button2.copyWithIsEnabled(false),
+ button3.copyWithIsEnabled(false),
+ button4.copyWithIsEnabled(false))
+ .inOrder();
assertThat(reportedCustomLayoutChanged.get(1))
- .containsExactly(button1, button2.copyWithIsEnabled(true))
+ .containsExactly(
+ button1.copyWithIsEnabled(false),
+ button2.copyWithIsEnabled(false),
+ button3.copyWithIsEnabled(false),
+ button4.copyWithIsEnabled(true))
.inOrder();
assertThat(getterCustomLayoutChanged).hasSize(2);
- assertThat(getterCustomLayoutChanged.get(0)).containsExactly(button1, button2).inOrder();
- assertThat(getterCustomLayoutChanged.get(1))
- .containsExactly(button1, button2.copyWithIsEnabled(true))
+ assertThat(getterCustomLayoutChanged.get(0))
+ .containsExactly(
+ button1.copyWithIsEnabled(false),
+ button2.copyWithIsEnabled(false),
+ button3.copyWithIsEnabled(false),
+ button4.copyWithIsEnabled(false))
.inOrder();
+ assertThat(getterCustomLayoutChanged.get(1))
+ .containsExactly(
+ button1.copyWithIsEnabled(false),
+ button2.copyWithIsEnabled(false),
+ button3.copyWithIsEnabled(false),
+ button4.copyWithIsEnabled(true))
+ .inOrder();
+ }
+
+ @Test
+ public void getCustomLayout_setAvailableCommandsOnPlayer_reportsCustomLayoutChanged()
+ throws Exception {
+ RemoteMediaSession session = createRemoteMediaSession(TEST_GET_CUSTOM_LAYOUT, null);
+ CommandButton button =
+ new CommandButton.Builder()
+ .setDisplayName("button")
+ .setIconResId(R.drawable.media3_notification_small_icon)
+ .setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
+ .build();
+ setupCustomLayout(session, ImmutableList.of(button));
+ CountDownLatch latch = new CountDownLatch(2);
+ List> 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(button.copyWithIsEnabled(true));
+ assertThat(reportedCustomLayouts).hasSize(2);
+ assertThat(reportedCustomLayouts.get(0)).containsExactly(button.copyWithIsEnabled(false));
+ assertThat(reportedCustomLayouts.get(1)).containsExactly(button.copyWithIsEnabled(true));
+ assertThat(getterCustomLayouts).hasSize(2);
+ assertThat(getterCustomLayouts.get(0)).containsExactly(button.copyWithIsEnabled(false));
+ assertThat(getterCustomLayouts.get(1)).containsExactly(button.copyWithIsEnabled(true));
}
@Test
@@ -341,6 +465,7 @@ public class MediaControllerTest {
CommandButton button2 =
new CommandButton.Builder()
.setDisplayName("button2")
+ .setEnabled(false)
.setIconResId(R.drawable.media3_notification_small_icon)
.setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
.build();
@@ -393,27 +518,31 @@ public class MediaControllerTest {
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
CommandButton button1Enabled = button1.copyWithIsEnabled(true);
- CommandButton button2Enabled = button2.copyWithIsEnabled(true);
- assertThat(initialCustomLayout).containsExactly(button1Enabled, button2Enabled).inOrder();
+ CommandButton button2Disabled = button2.copyWithIsEnabled(false);
+ CommandButton button3Disabled = button3.copyWithIsEnabled(false);
+ CommandButton button4Disabled = button4.copyWithIsEnabled(false);
+ assertThat(initialCustomLayout).containsExactly(button1Enabled, button2Disabled).inOrder();
assertThat(reportedCustomLayout)
.containsExactly(
- ImmutableList.of(button1Enabled, button2Enabled),
- ImmutableList.of(button3, button4),
- ImmutableList.of(button1Enabled, button2Enabled))
+ ImmutableList.of(button1Enabled, button2Disabled),
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
.inOrder();
assertThat(getterCustomLayout)
.containsExactly(
- ImmutableList.of(button1Enabled, button2Enabled),
- ImmutableList.of(button3, button4),
- ImmutableList.of(button1Enabled, button2Enabled))
+ ImmutableList.of(button1Enabled, button2Disabled),
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
.inOrder();
assertThat(reportedCustomLayoutChanged)
.containsExactly(
- ImmutableList.of(button3, button4), ImmutableList.of(button1Enabled, button2Enabled))
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
.inOrder();
assertThat(getterCustomLayoutChanged)
.containsExactly(
- ImmutableList.of(button3, button4), ImmutableList.of(button1Enabled, button2Enabled))
+ ImmutableList.of(button3Disabled, button4Disabled),
+ ImmutableList.of(button1Enabled, button2Disabled))
.inOrder();
session.cleanUp();
}
diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java
index 4690f2b80b..ebf8f709ef 100644
--- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java
+++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionServiceTest.java
@@ -319,7 +319,9 @@ public class MediaSessionServiceTest {
.isTrue();
assertThat(mediaControllerCompat.getPlaybackState().getActions())
.isEqualTo(PlaybackStateCompat.ACTION_SET_RATING);
- assertThat(remoteController.getCustomLayout()).containsExactly(button1, button2).inOrder();
+ assertThat(remoteController.getCustomLayout())
+ .containsExactly(button1.copyWithIsEnabled(false), button2.copyWithIsEnabled(false))
+ .inOrder();
assertThat(initialCustomLayoutInControllerCompat).isEmpty();
assertThat(LegacyConversions.convertToCustomLayout(mediaControllerCompat.getPlaybackState()))
.containsExactly(button1.copyWithIsEnabled(true), button3.copyWithIsEnabled(true))
diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java
index e3655c5578..172343b52d 100644
--- a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java
+++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java
@@ -207,7 +207,7 @@ public class MediaSessionProviderService extends Service {
.add(new SessionCommand("command1", Bundle.EMPTY))
.add(new SessionCommand("command2", Bundle.EMPTY))
.build(),
- Player.Commands.EMPTY);
+ new Player.Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build());
}
});
break;
@@ -549,7 +549,7 @@ public class MediaSessionProviderService extends Service {
() -> {
ImmutableList.Builder builder = new ImmutableList.Builder<>();
for (Bundle bundle : layout) {
- builder.add(CommandButton.fromBundle(bundle));
+ builder.add(CommandButton.fromBundle(bundle, MediaSessionStub.VERSION_INT));
}
MediaSession session = sessionMap.get(sessionId);
session.setCustomLayout(builder.build());
diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java
index a470ac7b2b..70bb2bedf3 100644
--- a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java
+++ b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java
@@ -381,7 +381,7 @@ public class RemoteMediaController {
ArrayList list = customLayoutBundle.getParcelableArrayList(KEY_COMMAND_BUTTON_LIST);
ImmutableList.Builder customLayout = new ImmutableList.Builder<>();
for (Bundle bundle : list) {
- customLayout.add(CommandButton.fromBundle(bundle));
+ customLayout.add(CommandButton.fromBundle(bundle, MediaSessionStub.VERSION_INT));
}
return customLayout.build();
}