Skip to content

Commit

Permalink
Propagate media3 session extras to media1 PlaybackStateCompat
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 642299178
  • Loading branch information
icbaker authored and copybara-github committed Jun 11, 2024
1 parent b145a96 commit 2456669
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 27 deletions.
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
and how to resolve the error if possible.
* Publish the code for the media3 controller test app that can be used to
test interactions with apps publishing a media session.
* Propagate extras passed to media3's
`MediaSession[Builder].setSessionExtras()` to a media1 controller's
`PlaybackStateCompat.getExtras()`.
* UI:
* Add customisation of various icons in `PlayerControlView` through xml
attributes to allow different drawables per `PlayerView` instance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ public MediaSessionImpl(
playIfSuppressed,
customLayout,
connectionResult.availableSessionCommands,
connectionResult.availablePlayerCommands);
connectionResult.availablePlayerCommands,
sessionExtras);
this.playerWrapper = playerWrapper;
postOrRun(
applicationHandler,
Expand All @@ -265,7 +266,8 @@ public void setPlayer(Player player) {
playIfSuppressed,
playerWrapper.getCustomLayout(),
playerWrapper.getAvailableSessionCommands(),
playerWrapper.getAvailablePlayerCommands()));
playerWrapper.getAvailablePlayerCommands(),
playerWrapper.getLegacyExtras()));
}

private void setPlayerInternal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,8 @@ public void setCustomLayout(int seq, List<CommandButton> layout) {
@Override
public void onSessionExtrasChanged(int seq, Bundle sessionExtras) {
sessionCompat.setExtras(sessionExtras);
sessionImpl.getPlayerWrapper().setLegacyExtras(sessionExtras);
sessionCompat.setPlaybackState(sessionImpl.getPlayerWrapper().createPlaybackStateCompat());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
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.common.util.Util.msToUs;
Expand Down Expand Up @@ -70,6 +71,7 @@
private int legacyStatusCode;
@Nullable private String legacyErrorMessage;
@Nullable private Bundle legacyErrorExtras;
@Nullable private Bundle legacyExtras;
private ImmutableList<CommandButton> customLayout;
private SessionCommands availableSessionCommands;
private Commands availablePlayerCommands;
Expand All @@ -79,12 +81,14 @@ public PlayerWrapper(
boolean playIfSuppressed,
ImmutableList<CommandButton> customLayout,
SessionCommands availableSessionCommands,
Commands availablePlayerCommands) {
Commands availablePlayerCommands,
@Nullable Bundle legacyExtras) {
super(player);
this.playIfSuppressed = playIfSuppressed;
this.customLayout = customLayout;
this.availableSessionCommands = availableSessionCommands;
this.availablePlayerCommands = availablePlayerCommands;
this.legacyExtras = legacyExtras;
legacyStatusCode = STATUS_CODE_SUCCESS_COMPAT;
}

Expand All @@ -110,6 +114,19 @@ public void setCustomLayout(ImmutableList<CommandButton> customLayout) {
return customLayout;
}

public void setLegacyExtras(@Nullable Bundle extras) {
if (extras != null) {
checkArgument(!extras.containsKey(EXTRAS_KEY_PLAYBACK_SPEED_COMPAT));
checkArgument(!extras.containsKey(EXTRAS_KEY_MEDIA_ID_COMPAT));
}
this.legacyExtras = extras;
}

@Nullable
public Bundle getLegacyExtras() {
return legacyExtras;
}

/**
* Sets the legacy error code.
*
Expand Down Expand Up @@ -1000,6 +1017,13 @@ public Size getSurfaceSize() {

public PlaybackStateCompat createPlaybackStateCompat() {
if (legacyStatusCode != STATUS_CODE_SUCCESS_COMPAT) {
Bundle extras;
if (legacyExtras != null) {
extras = new Bundle(checkNotNull(legacyErrorExtras));
extras.putAll(legacyExtras);
} else {
extras = checkNotNull(legacyErrorExtras);
}
return new PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_ERROR,
Expand All @@ -1009,7 +1033,7 @@ public PlaybackStateCompat createPlaybackStateCompat() {
.setActions(0)
.setBufferedPosition(0)
.setErrorMessage(legacyStatusCode, checkNotNull(legacyErrorMessage))
.setExtras(checkNotNull(legacyErrorExtras))
.setExtras(extras)
.build();
}
@Nullable PlaybackException playerError = getPlayerError();
Expand All @@ -1027,7 +1051,7 @@ public PlaybackStateCompat createPlaybackStateCompat() {
: MediaSessionCompat.QueueItem.UNKNOWN_ID;
float playbackSpeed = getPlaybackParameters().speed;
float sessionPlaybackSpeed = isPlaying() ? playbackSpeed : 0f;
Bundle extras = new Bundle();
Bundle extras = legacyExtras != null ? new Bundle(legacyExtras) : new Bundle();
extras.putFloat(EXTRAS_KEY_PLAYBACK_SPEED_COMPAT, playbackSpeed);
@Nullable MediaItem currentMediaItem = getCurrentMediaItemWithCommandCheck();
if (currentMediaItem != null && !MediaItem.DEFAULT_MEDIA_ID.equals(currentMediaItem.mediaId)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public void setUp() {
/* playIfSuppressed= */ true,
ImmutableList.of(),
SessionCommands.EMPTY,
Player.Commands.EMPTY);
Player.Commands.EMPTY,
/* legacyExtras= */ null);
when(player.isCommandAvailable(anyInt())).thenReturn(true);
when(player.getApplicationLooper()).thenReturn(Looper.myLooper());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_SET_SHOW_PLAY_BUTTON_IF_SUPPRESSED_TO_FALSE;
import static androidx.media3.test.session.common.TestUtils.LONG_TIMEOUT_MS;
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
import static androidx.test.ext.truth.os.BundleSubject.assertThat;
import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

Expand Down Expand Up @@ -999,33 +1000,106 @@ public void onPlaybackStateChanged(PlaybackStateCompat state) {
}

@Test
public void setSessionExtras_cnExtrasChangedCalled() throws Exception {
public void setSessionExtras_toAllControllers_extrasAndStateCallbacks() throws Exception {
Bundle sessionExtras = new Bundle();
sessionExtras.putString("key-0", "value-0");
CountDownLatch latch = new CountDownLatch(1);
List<Bundle> receivedSessionExtras = new ArrayList<>();
CountDownLatch onExtrasChangedCalled = new CountDownLatch(1);
CountDownLatch onPlaybackStateChangedCalled = new CountDownLatch(1);
AtomicReference<Bundle> sessionExtrasFromCallback = new AtomicReference<>();
AtomicReference<Bundle> sessionExtrasFromController = new AtomicReference<>();
AtomicReference<Bundle> playbackStateExtrasFromCallback = new AtomicReference<>();
AtomicReference<Bundle> playbackStateExtrasFromController = new AtomicReference<>();
MediaControllerCompat.Callback callback =
new MediaControllerCompat.Callback() {
@Override
public void onExtrasChanged(Bundle extras) {
receivedSessionExtras.add(extras);
receivedSessionExtras.add(controllerCompat.getExtras());
latch.countDown();
sessionExtrasFromCallback.set(extras);
sessionExtrasFromController.set(controllerCompat.getExtras());
onExtrasChangedCalled.countDown();
}

@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
playbackStateExtrasFromCallback.set(state.getExtras());
playbackStateExtrasFromController.set(controllerCompat.getPlaybackState().getExtras());
onPlaybackStateChangedCalled.countDown();
}
};
controllerCompat.registerCallback(callback, handler);

session.setSessionExtras(sessionExtras);

assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(TestUtils.equals(receivedSessionExtras.get(0), sessionExtras)).isTrue();
assertThat(TestUtils.equals(receivedSessionExtras.get(1), sessionExtras)).isTrue();
assertThat(onExtrasChangedCalled.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(onPlaybackStateChangedCalled.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(sessionExtrasFromCallback.get()).hasSize(1);
assertThat(sessionExtrasFromCallback.get()).string("key-0").isEqualTo("value-0");
assertThat(sessionExtrasFromController.get()).hasSize(1);
assertThat(sessionExtrasFromController.get()).string("key-0").isEqualTo("value-0");
assertThat(playbackStateExtrasFromCallback.get()).hasSize(2);
assertThat(playbackStateExtrasFromCallback.get())
.doubleFloat(MediaConstants.EXTRAS_KEY_PLAYBACK_SPEED_COMPAT)
.isEqualTo(0.0);
assertThat(playbackStateExtrasFromCallback.get()).string("key-0").isEqualTo("value-0");
assertThat(playbackStateExtrasFromController.get()).hasSize(2);
assertThat(playbackStateExtrasFromController.get())
.doubleFloat(MediaConstants.EXTRAS_KEY_PLAYBACK_SPEED_COMPAT)
.isEqualTo(0.0);
assertThat(playbackStateExtrasFromController.get()).string("key-0").isEqualTo("value-0");
}

@Test
public void setSessionExtras_toMediaNotificationControllers_extrasAndStateCallbacks()
throws Exception {
Bundle sessionExtras = new Bundle();
sessionExtras.putString("key-0", "value-0");
CountDownLatch onExtrasChangedCalled = new CountDownLatch(1);
CountDownLatch onPlaybackStateChangedCalled = new CountDownLatch(1);
AtomicReference<Bundle> sessionExtrasFromCallback = new AtomicReference<>();
AtomicReference<Bundle> sessionExtrasFromController = new AtomicReference<>();
AtomicReference<Bundle> playbackStateExtrasFromCallback = new AtomicReference<>();
AtomicReference<Bundle> playbackStateExtrasFromController = new AtomicReference<>();
MediaControllerCompat.Callback callback =
new MediaControllerCompat.Callback() {
@Override
public void onExtrasChanged(Bundle extras) {
sessionExtrasFromCallback.set(extras);
sessionExtrasFromController.set(controllerCompat.getExtras());
onExtrasChangedCalled.countDown();
}

@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
playbackStateExtrasFromCallback.set(state.getExtras());
playbackStateExtrasFromController.set(controllerCompat.getPlaybackState().getExtras());
onPlaybackStateChangedCalled.countDown();
}
};
controllerCompat.registerCallback(callback, handler);

session.setSessionExtras(/* controllerKey= */ NOTIFICATION_CONTROLLER_KEY, sessionExtras);

assertThat(onExtrasChangedCalled.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(onPlaybackStateChangedCalled.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(sessionExtrasFromCallback.get()).hasSize(1);
assertThat(sessionExtrasFromCallback.get()).string("key-0").isEqualTo("value-0");
assertThat(sessionExtrasFromController.get()).hasSize(1);
assertThat(sessionExtrasFromController.get()).string("key-0").isEqualTo("value-0");
assertThat(playbackStateExtrasFromCallback.get()).hasSize(2);
assertThat(playbackStateExtrasFromCallback.get())
.doubleFloat(MediaConstants.EXTRAS_KEY_PLAYBACK_SPEED_COMPAT)
.isEqualTo(0.0);
assertThat(playbackStateExtrasFromCallback.get()).string("key-0").isEqualTo("value-0");
assertThat(playbackStateExtrasFromController.get()).hasSize(2);
assertThat(playbackStateExtrasFromController.get())
.doubleFloat(MediaConstants.EXTRAS_KEY_PLAYBACK_SPEED_COMPAT)
.isEqualTo(0.0);
assertThat(playbackStateExtrasFromController.get()).string("key-0").isEqualTo("value-0");
}

@Test
public void sendError_toAllControllers_onPlaybackStateChangedToErrorStateAndWithCorrectErrorData()
throws Exception {
CountDownLatch latch = new CountDownLatch(2);
CountDownLatch latch = new CountDownLatch(3);
List<PlaybackStateCompat> playbackStates = new ArrayList<>();
MediaControllerCompat.Callback callback =
new MediaControllerCompat.Callback() {
Expand All @@ -1036,9 +1110,12 @@ public void onPlaybackStateChanged(PlaybackStateCompat state) {
}
};
controllerCompat.registerCallback(callback, handler);
Bundle sessionExtras = new Bundle();
sessionExtras.putString("initialKey", "initialValue");
session.setSessionExtras(sessionExtras);
PlaybackStateCompat initialPlaybackStateCompat = controllerCompat.getPlaybackState();
Bundle errorBundle = new Bundle();
errorBundle.putInt("intKey", 99);
errorBundle.putInt("errorKey", 99);

session.sendError(
/* controllerKey= */ null,
Expand All @@ -1047,27 +1124,38 @@ public void onPlaybackStateChanged(PlaybackStateCompat state) {
errorBundle);

assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(playbackStates).hasSize(2);
PlaybackStateCompat errorPlaybackStateCompat = playbackStates.get(0);
assertThat(playbackStates).hasSize(3);

// Skip the playback state from the first setSessionExtras() call.
PlaybackStateCompat errorPlaybackStateCompat = playbackStates.get(1);
assertThat(errorPlaybackStateCompat.getState()).isEqualTo(PlaybackStateCompat.STATE_ERROR);
assertThat(errorPlaybackStateCompat.getErrorCode()).isEqualTo(1);
assertThat(errorPlaybackStateCompat.getErrorMessage().toString())
.isEqualTo(context.getString(R.string.authentication_required));
PlaybackStateCompat resolvedPlaybackStateCompat = playbackStates.get(1);
assertThat(errorPlaybackStateCompat.getExtras()).hasSize(2);
assertThat(errorPlaybackStateCompat.getExtras()).integer("errorKey").isEqualTo(99);
assertThat(errorPlaybackStateCompat.getExtras()).string("initialKey").isEqualTo("initialValue");

PlaybackStateCompat resolvedPlaybackStateCompat = playbackStates.get(2);
assertThat(resolvedPlaybackStateCompat.getState())
.isEqualTo(initialPlaybackStateCompat.getState());
assertThat(resolvedPlaybackStateCompat.getErrorCode())
.isEqualTo(initialPlaybackStateCompat.getErrorCode());
assertThat(resolvedPlaybackStateCompat.getErrorMessage()).isNull();
assertThat(resolvedPlaybackStateCompat.getActions())
.isEqualTo(initialPlaybackStateCompat.getActions());
assertThat(resolvedPlaybackStateCompat.getExtras())
.hasSize(initialPlaybackStateCompat.getExtras().size());
assertThat(resolvedPlaybackStateCompat.getExtras())
.string("initialKey")
.isEqualTo(initialPlaybackStateCompat.getExtras().getString("initialKey"));
}

@Test
public void
sendError_toMediaNotificationControllers_onPlaybackStateChangedToErrorStateAndWithCorrectErrorData()
throws Exception {
CountDownLatch latch = new CountDownLatch(2);
CountDownLatch latch = new CountDownLatch(3);
List<PlaybackStateCompat> playbackStates = new ArrayList<>();
MediaControllerCompat.Callback callback =
new MediaControllerCompat.Callback() {
Expand All @@ -1078,33 +1166,46 @@ public void onPlaybackStateChanged(PlaybackStateCompat state) {
}
};
controllerCompat.registerCallback(callback, handler);
Bundle sessionExtras = new Bundle();
sessionExtras.putString("initialKey", "initialValue");
session.setSessionExtras(/* controllerKey= */ NOTIFICATION_CONTROLLER_KEY, sessionExtras);
PlaybackStateCompat initialPlaybackStateCompat = controllerCompat.getPlaybackState();
Bundle errorBundle = new Bundle();
errorBundle.putInt("intKey", 99);

Bundle errorBundle = new Bundle();
errorBundle.putInt("errorKey", 99);
session.sendError(
/* controllerKey= */ NOTIFICATION_CONTROLLER_KEY,
/* errorCode= */ 1,
R.string.authentication_required,
errorBundle);

assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(playbackStates).hasSize(2);
PlaybackStateCompat errorPlaybackStateCompat = playbackStates.get(0);
assertThat(playbackStates).hasSize(3);

// Skip the playback state from the first setSessionExtras() call.
PlaybackStateCompat errorPlaybackStateCompat = playbackStates.get(1);
assertThat(errorPlaybackStateCompat.getState()).isEqualTo(PlaybackStateCompat.STATE_ERROR);
assertThat(errorPlaybackStateCompat.getErrorCode()).isEqualTo(1);
assertThat(errorPlaybackStateCompat.getErrorMessage().toString())
.isEqualTo(context.getString(R.string.authentication_required));
assertThat(errorPlaybackStateCompat.getActions()).isEqualTo(0);
assertThat(TestUtils.equals(errorPlaybackStateCompat.getExtras(), errorBundle)).isTrue();
PlaybackStateCompat resolvedPlaybackStateCompat = playbackStates.get(1);
assertThat(errorPlaybackStateCompat.getExtras()).hasSize(2);
assertThat(errorPlaybackStateCompat.getExtras()).string("initialKey").isEqualTo("initialValue");
assertThat(errorPlaybackStateCompat.getExtras()).integer("errorKey").isEqualTo(99);

PlaybackStateCompat resolvedPlaybackStateCompat = playbackStates.get(2);
assertThat(resolvedPlaybackStateCompat.getState())
.isEqualTo(initialPlaybackStateCompat.getState());
assertThat(resolvedPlaybackStateCompat.getErrorCode())
.isEqualTo(initialPlaybackStateCompat.getErrorCode());
assertThat(resolvedPlaybackStateCompat.getErrorMessage()).isNull();
assertThat(resolvedPlaybackStateCompat.getActions())
.isEqualTo(initialPlaybackStateCompat.getActions());
assertThat(resolvedPlaybackStateCompat.getExtras())
.hasSize(initialPlaybackStateCompat.getExtras().size());
assertThat(resolvedPlaybackStateCompat.getExtras())
.string("initialKey")
.isEqualTo(initialPlaybackStateCompat.getExtras().getString("initialKey"));
}

@Test
Expand Down

0 comments on commit 2456669

Please sign in to comment.