Implement session extras for Media3 and legacy controllers
This provides an (unstable) API for apps to broadcast session extras Bundle to all connected controllers and set the extras in the legacy session. Similar to the custom layout, the extras Bundle is not part of the Media3 session state. This means that when a Media3 controller connects to the session after the broadcast, the extras needs to be sent to that controller in `MediaSession.Callback.onPostConnect(MediaSession session, ControllerInfo controller)`. PiperOrigin-RevId: 451871731
This commit is contained in:
parent
a629d09458
commit
85a936ecb1
@ -42,7 +42,8 @@ oneway interface IMediaController {
|
|||||||
void onAvailableCommandsChangedFromSession(
|
void onAvailableCommandsChangedFromSession(
|
||||||
int seq, in Bundle sessionCommandsBundle, in Bundle playerCommandsBundle) = 3009;
|
int seq, in Bundle sessionCommandsBundle, in Bundle playerCommandsBundle) = 3009;
|
||||||
void onRenderedFirstFrame(int seq) = 3010;
|
void onRenderedFirstFrame(int seq) = 3010;
|
||||||
// Next Id for MediaController: 3011
|
void onExtrasChanged(int seq, in Bundle extras) = 3011;
|
||||||
|
// Next Id for MediaController: 3012
|
||||||
|
|
||||||
void onChildrenChanged(
|
void onChildrenChanged(
|
||||||
int seq, String parentId, int itemCount, in @nullable Bundle libraryParams) = 4000;
|
int seq, String parentId, int itemCount, in @nullable Bundle libraryParams) = 4000;
|
||||||
|
@ -151,8 +151,6 @@ public final class MediaConstants {
|
|||||||
*/
|
*/
|
||||||
public static final int ERROR_CODE_AUTHENTICATION_EXPIRED_COMPAT = 3;
|
public static final int ERROR_CODE_AUTHENTICATION_EXPIRED_COMPAT = 3;
|
||||||
|
|
||||||
/* package */ static final String SESSION_COMMAND_ON_EXTRAS_CHANGED =
|
|
||||||
"androidx.media3.session.SESSION_COMMAND_ON_EXTRAS_CHANGED";
|
|
||||||
/* package */ static final String SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED =
|
/* package */ static final String SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED =
|
||||||
"androidx.media3.session.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED";
|
"androidx.media3.session.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED";
|
||||||
/* package */ static final String SESSION_COMMAND_REQUEST_SESSION3_TOKEN =
|
/* package */ static final String SESSION_COMMAND_REQUEST_SESSION3_TOKEN =
|
||||||
|
@ -322,6 +322,14 @@ public class MediaController implements Player {
|
|||||||
MediaController controller, SessionCommand command, Bundle args) {
|
MediaController controller, SessionCommand command, Bundle args) {
|
||||||
return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_ERROR_NOT_SUPPORTED));
|
return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_ERROR_NOT_SUPPORTED));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the session extras have changed.
|
||||||
|
*
|
||||||
|
* @param controller The controller.
|
||||||
|
* @param extras The session extras that have changed.
|
||||||
|
*/
|
||||||
|
default void onExtrasChanged(MediaController controller, Bundle extras) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ interface ConnectionCallback {
|
/* package */ interface ConnectionCallback {
|
||||||
|
@ -2598,6 +2598,13 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onExtrasChanged(Bundle extras) {
|
||||||
|
if (!isConnected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance.notifyControllerListener(listener -> listener.onExtrasChanged(instance, extras));
|
||||||
|
}
|
||||||
|
|
||||||
public void onRenderedFirstFrame() {
|
public void onRenderedFirstFrame() {
|
||||||
listeners.sendEvent(/* eventFlag= */ C.INDEX_UNSET, Listener::onRenderedFirstFrame);
|
listeners.sendEvent(/* eventFlag= */ C.INDEX_UNSET, Listener::onRenderedFirstFrame);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ import static androidx.media3.session.MediaConstants.MEDIA_URI_QUERY_QUERY;
|
|||||||
import static androidx.media3.session.MediaConstants.MEDIA_URI_QUERY_URI;
|
import static androidx.media3.session.MediaConstants.MEDIA_URI_QUERY_URI;
|
||||||
import static androidx.media3.session.MediaConstants.MEDIA_URI_SET_MEDIA_URI_PREFIX;
|
import static androidx.media3.session.MediaConstants.MEDIA_URI_SET_MEDIA_URI_PREFIX;
|
||||||
import static androidx.media3.session.MediaConstants.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED;
|
import static androidx.media3.session.MediaConstants.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED;
|
||||||
import static androidx.media3.session.MediaConstants.SESSION_COMMAND_ON_EXTRAS_CHANGED;
|
|
||||||
import static androidx.media3.session.MediaUtils.POSITION_DIFF_TOLERANCE_MS;
|
import static androidx.media3.session.MediaUtils.POSITION_DIFF_TOLERANCE_MS;
|
||||||
import static androidx.media3.session.MediaUtils.calculateBufferedPercentage;
|
import static androidx.media3.session.MediaUtils.calculateBufferedPercentage;
|
||||||
import static androidx.media3.session.SessionResult.RESULT_INFO_SKIPPED;
|
import static androidx.media3.session.SessionResult.RESULT_INFO_SKIPPED;
|
||||||
@ -1606,14 +1605,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExtrasChanged(Bundle extras) {
|
public void onExtrasChanged(Bundle extras) {
|
||||||
instance.notifyControllerListener(
|
instance.notifyControllerListener(listener -> listener.onExtrasChanged(instance, extras));
|
||||||
listener ->
|
|
||||||
ignoreFuture(
|
|
||||||
listener.onCustomCommand(
|
|
||||||
instance,
|
|
||||||
new SessionCommand(
|
|
||||||
SESSION_COMMAND_ON_EXTRAS_CHANGED, /* extras= */ Bundle.EMPTY),
|
|
||||||
extras)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -183,6 +183,11 @@ import java.util.List;
|
|||||||
isTimelineExcluded));
|
isTimelineExcluded));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExtrasChanged(int seq, Bundle extras) {
|
||||||
|
dispatchControllerTaskOnHandler(controller -> controller.onExtrasChanged(extras));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRenderedFirstFrame(int seq) {
|
public void onRenderedFirstFrame(int seq) {
|
||||||
dispatchControllerTaskOnHandler(MediaControllerImplBase::onRenderedFirstFrame);
|
dispatchControllerTaskOnHandler(MediaControllerImplBase::onRenderedFirstFrame);
|
||||||
|
@ -702,6 +702,32 @@ public class MediaSession {
|
|||||||
impl.broadcastCustomCommand(command, args);
|
impl.broadcastCustomCommand(command, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the session extras to connected controllers.
|
||||||
|
*
|
||||||
|
* <p>This is a synchronous call and doesn't wait for results from the controllers.
|
||||||
|
*
|
||||||
|
* @param sessionExtras The session extras.
|
||||||
|
*/
|
||||||
|
public void setSessionExtras(Bundle sessionExtras) {
|
||||||
|
checkNotNull(sessionExtras);
|
||||||
|
impl.setSessionExtras(sessionExtras);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the session extras to the connected controller.
|
||||||
|
*
|
||||||
|
* <p>This is a synchronous call and doesn't wait for results from the controller.
|
||||||
|
*
|
||||||
|
* @param controller The controller to send the extras to.
|
||||||
|
* @param sessionExtras The session extras.
|
||||||
|
*/
|
||||||
|
public void setSessionExtras(ControllerInfo controller, Bundle sessionExtras) {
|
||||||
|
checkNotNull(controller, "controller must not be null");
|
||||||
|
checkNotNull(sessionExtras);
|
||||||
|
impl.setSessionExtras(controller, sessionExtras);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a custom command to a specific controller.
|
* Sends a custom command to a specific controller.
|
||||||
*
|
*
|
||||||
@ -1119,6 +1145,8 @@ public class MediaSession {
|
|||||||
|
|
||||||
default void setCustomLayout(int seq, List<CommandButton> layout) throws RemoteException {}
|
default void setCustomLayout(int seq, List<CommandButton> layout) throws RemoteException {}
|
||||||
|
|
||||||
|
default void onSessionExtrasChanged(int seq, Bundle sessionExtras) throws RemoteException {}
|
||||||
|
|
||||||
default void sendCustomCommand(int seq, SessionCommand command, Bundle args)
|
default void sendCustomCommand(int seq, SessionCommand command, Bundle args)
|
||||||
throws RemoteException {}
|
throws RemoteException {}
|
||||||
|
|
||||||
|
@ -342,6 +342,18 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
(controller, seq) -> controller.setCustomLayout(seq, layout));
|
(controller, seq) -> controller.setCustomLayout(seq, layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSessionExtras(Bundle sessionExtras) {
|
||||||
|
dispatchRemoteControllerTaskWithoutReturn(
|
||||||
|
(controller, seq) -> controller.onSessionExtrasChanged(seq, sessionExtras));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionExtras(ControllerInfo controller, Bundle sessionExtras) {
|
||||||
|
if (sessionStub.getConnectedControllersManager().isConnected(controller)) {
|
||||||
|
dispatchRemoteControllerTaskWithoutReturn(
|
||||||
|
controller, (callback, seq) -> callback.onSessionExtrasChanged(seq, sessionExtras));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setAvailableCommands(
|
public void setAvailableCommands(
|
||||||
ControllerInfo controller, SessionCommands sessionCommands, Player.Commands playerCommands) {
|
ControllerInfo controller, SessionCommands sessionCommands, Player.Commands playerCommands) {
|
||||||
if (sessionStub.getConnectedControllersManager().isConnected(controller)) {
|
if (sessionStub.getConnectedControllersManager().isConnected(controller)) {
|
||||||
|
@ -886,6 +886,11 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
.setPlaybackState(sessionImpl.getPlayerWrapper().createPlaybackStateCompat());
|
.setPlaybackState(sessionImpl.getPlayerWrapper().createPlaybackStateCompat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSessionExtrasChanged(int seq, Bundle sessionExtras) {
|
||||||
|
sessionImpl.getSessionCompat().setExtras(sessionExtras);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayWhenReadyChanged(
|
public void onPlayWhenReadyChanged(
|
||||||
int seq, boolean playWhenReady, @Player.PlaybackSuppressionReason int reason)
|
int seq, boolean playWhenReady, @Player.PlaybackSuppressionReason int reason)
|
||||||
|
@ -1801,6 +1801,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
iController.onRenderedFirstFrame(seq);
|
iController.onRenderedFirstFrame(seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSessionExtrasChanged(int seq, Bundle sessionExtras) throws RemoteException {
|
||||||
|
iController.onExtrasChanged(seq, sessionExtras);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return ObjectsCompat.hash(getCallbackBinder());
|
return ObjectsCompat.hash(getCallbackBinder());
|
||||||
|
@ -32,6 +32,8 @@ interface IRemoteMediaSession {
|
|||||||
void release(String sessionId);
|
void release(String sessionId);
|
||||||
void setAvailableCommands(String sessionId, in Bundle sessionCommands, in Bundle playerCommands);
|
void setAvailableCommands(String sessionId, in Bundle sessionCommands, in Bundle playerCommands);
|
||||||
void setCustomLayout(String sessionId, in List<Bundle> layout);
|
void setCustomLayout(String sessionId, in List<Bundle> layout);
|
||||||
|
void setSessionExtras(String sessionId, in Bundle extras);
|
||||||
|
void setSessionExtrasForController(String sessionId, in String controllerKey, in Bundle extras);
|
||||||
|
|
||||||
// Player Methods
|
// Player Methods
|
||||||
void setPlayWhenReady(String sessionId, boolean playWhenReady, int reason);
|
void setPlayWhenReady(String sessionId, boolean playWhenReady, int reason);
|
||||||
|
@ -41,4 +41,5 @@ interface IRemoteMediaSessionCompat {
|
|||||||
void setRatingType(String sessionTag, int type);
|
void setRatingType(String sessionTag, int type);
|
||||||
void sendSessionEvent(String sessionTag, String event, in Bundle extras);
|
void sendSessionEvent(String sessionTag, String event, in Bundle extras);
|
||||||
void setCaptioningEnabled(String sessionTag, boolean enabled);
|
void setCaptioningEnabled(String sessionTag, boolean enabled);
|
||||||
|
void setSessionExtras(String sessionTag, in Bundle extras);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ public class MediaSessionConstants {
|
|||||||
|
|
||||||
// Bundle keys
|
// Bundle keys
|
||||||
public static final String KEY_AVAILABLE_SESSION_COMMANDS = "availableSessionCommands";
|
public static final String KEY_AVAILABLE_SESSION_COMMANDS = "availableSessionCommands";
|
||||||
|
public static final String KEY_CONTROLLER = "controllerKey";
|
||||||
|
|
||||||
private MediaSessionConstants() {}
|
private MediaSessionConstants() {}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import android.support.v4.media.session.MediaSessionCompat;
|
|||||||
import android.support.v4.media.session.PlaybackStateCompat;
|
import android.support.v4.media.session.PlaybackStateCompat;
|
||||||
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
||||||
import androidx.media3.test.session.common.MainLooperTestRule;
|
import androidx.media3.test.session.common.MainLooperTestRule;
|
||||||
|
import androidx.media3.test.session.common.TestUtils;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
@ -137,4 +138,42 @@ public class MediaControllerCompatCallbackWithMediaSessionCompatTest {
|
|||||||
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
|
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
|
||||||
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting the session extras is used for instance by <a
|
||||||
|
* href="http://android-doc.github.io/reference/android/support/wearable/media/MediaControlConstants.html">
|
||||||
|
* Wear OS</a> and System UI (starting with T) to receive extras for UI customization. An app
|
||||||
|
* needs a way to set the session extras that are stored in the legacy session and broadcast to
|
||||||
|
* the connected controllers.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void setExtras_onExtrasChangedCalled() throws Exception {
|
||||||
|
Bundle sessionExtras = new Bundle();
|
||||||
|
sessionExtras.putString("key-1", "value-1");
|
||||||
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
|
MediaSessionCompat.Token sessionToken = session.getSessionToken();
|
||||||
|
List<Bundle> receivedSessionExtras = new ArrayList<>();
|
||||||
|
threadTestRule
|
||||||
|
.getHandler()
|
||||||
|
.postAndSync(
|
||||||
|
() -> {
|
||||||
|
MediaControllerCompat mediaControllerCompat =
|
||||||
|
new MediaControllerCompat(context, sessionToken);
|
||||||
|
mediaControllerCompat.registerCallback(
|
||||||
|
new MediaControllerCompat.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onExtrasChanged(Bundle extras) {
|
||||||
|
receivedSessionExtras.add(extras);
|
||||||
|
receivedSessionExtras.add(mediaControllerCompat.getExtras());
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
session.setExtras(sessionExtras);
|
||||||
|
|
||||||
|
assertThat(countDownLatch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
|
assertThat(TestUtils.equals(receivedSessionExtras.get(0), sessionExtras)).isTrue();
|
||||||
|
assertThat(TestUtils.equals(receivedSessionExtras.get(1), sessionExtras)).isTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -819,6 +819,30 @@ public class MediaControllerCompatCallbackWithMediaSessionTest {
|
|||||||
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setSessionExtras_cnExtrasChangedCalled() throws Exception {
|
||||||
|
Bundle sessionExtras = new Bundle();
|
||||||
|
sessionExtras.putString("key-0", "value-0");
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
List<Bundle> receivedSessionExtras = new ArrayList<>();
|
||||||
|
MediaControllerCompat.Callback callback =
|
||||||
|
new MediaControllerCompat.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onExtrasChanged(Bundle extras) {
|
||||||
|
receivedSessionExtras.add(extras);
|
||||||
|
receivedSessionExtras.add(controllerCompat.getExtras());
|
||||||
|
latch.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();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void currentMediaItemChange() throws Exception {
|
public void currentMediaItemChange() throws Exception {
|
||||||
int testItemIndex = 3;
|
int testItemIndex = 3;
|
||||||
|
@ -28,6 +28,7 @@ import static androidx.media3.session.SessionResult.RESULT_SUCCESS;
|
|||||||
import static androidx.media3.test.session.common.CommonConstants.DEFAULT_TEST_NAME;
|
import static androidx.media3.test.session.common.CommonConstants.DEFAULT_TEST_NAME;
|
||||||
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA3_LIBRARY_SERVICE;
|
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA3_LIBRARY_SERVICE;
|
||||||
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA3_SESSION_SERVICE;
|
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA3_SESSION_SERVICE;
|
||||||
|
import static androidx.media3.test.session.common.MediaSessionConstants.KEY_CONTROLLER;
|
||||||
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_CONTROLLER_LISTENER_SESSION_REJECTS;
|
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_CONTROLLER_LISTENER_SESSION_REJECTS;
|
||||||
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_WITH_CUSTOM_COMMANDS;
|
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_WITH_CUSTOM_COMMANDS;
|
||||||
import static androidx.media3.test.session.common.TestUtils.LONG_TIMEOUT_MS;
|
import static androidx.media3.test.session.common.TestUtils.LONG_TIMEOUT_MS;
|
||||||
@ -1800,6 +1801,55 @@ public class MediaControllerListenerTest {
|
|||||||
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setSessionExtras_onExtrasChangedCalled() throws Exception {
|
||||||
|
Bundle sessionExtras = TestUtils.createTestBundle();
|
||||||
|
sessionExtras.putString("key-0", "value-0");
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
List<Bundle> receivedSessionExtras = new ArrayList<>();
|
||||||
|
MediaController.Listener listener =
|
||||||
|
new MediaController.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onExtrasChanged(MediaController controller, Bundle extras) {
|
||||||
|
receivedSessionExtras.add(extras);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
controllerTestRule.createController(
|
||||||
|
remoteSession.getToken(), /* connectionHints= */ null, listener);
|
||||||
|
|
||||||
|
remoteSession.setSessionExtras(sessionExtras);
|
||||||
|
|
||||||
|
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
|
assertThat(receivedSessionExtras).hasSize(1);
|
||||||
|
assertThat(TestUtils.equals(receivedSessionExtras.get(0), sessionExtras)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setSessionExtras_specificMedia3Controller_onExtrasChangedCalled() throws Exception {
|
||||||
|
Bundle sessionExtras = TestUtils.createTestBundle();
|
||||||
|
sessionExtras.putString("key-0", "value-0");
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
List<Bundle> receivedSessionExtras = new ArrayList<>();
|
||||||
|
MediaController.Listener listener =
|
||||||
|
new MediaController.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onExtrasChanged(MediaController controller, Bundle extras) {
|
||||||
|
receivedSessionExtras.add(extras);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Bundle connectionHints = new Bundle();
|
||||||
|
connectionHints.putString(KEY_CONTROLLER, "controller_key_1");
|
||||||
|
controllerTestRule.createController(remoteSession.getToken(), connectionHints, listener);
|
||||||
|
|
||||||
|
remoteSession.setSessionExtras("controller_key_1", sessionExtras);
|
||||||
|
|
||||||
|
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
|
assertThat(receivedSessionExtras).hasSize(1);
|
||||||
|
assertThat(TestUtils.equals(receivedSessionExtras.get(0), sessionExtras)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onVideoSizeChanged() throws Exception {
|
public void onVideoSizeChanged() throws Exception {
|
||||||
VideoSize testVideoSize =
|
VideoSize testVideoSize =
|
||||||
|
@ -32,6 +32,7 @@ import androidx.media3.common.FlagSet;
|
|||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
||||||
import androidx.media3.test.session.common.MainLooperTestRule;
|
import androidx.media3.test.session.common.MainLooperTestRule;
|
||||||
|
import androidx.media3.test.session.common.TestUtils;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
@ -168,4 +169,26 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
|
|||||||
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
|
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
|
||||||
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setSessionExtras_onExtrasChangedCalled() throws Exception {
|
||||||
|
Bundle sessionExtras = new Bundle();
|
||||||
|
sessionExtras.putString("key-1", "value-1");
|
||||||
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
|
List<Bundle> receivedSessionExtras = new ArrayList<>();
|
||||||
|
controllerTestRule.createController(
|
||||||
|
session.getSessionToken(),
|
||||||
|
new MediaController.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onExtrasChanged(MediaController controller, Bundle extras) {
|
||||||
|
receivedSessionExtras.add(extras);
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
session.setExtras(sessionExtras);
|
||||||
|
|
||||||
|
assertThat(countDownLatch.await(1_000, MILLISECONDS)).isTrue();
|
||||||
|
assertThat(TestUtils.equals(receivedSessionExtras.get(0), sessionExtras)).isTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,5 +216,11 @@ public class MediaSessionCompatProviderService extends Service {
|
|||||||
MediaSessionCompat session = sessionMap.get(sessionTag);
|
MediaSessionCompat session = sessionMap.get(sessionTag);
|
||||||
session.setCaptioningEnabled(enabled);
|
session.setCaptioningEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSessionExtras(String sessionTag, Bundle extras) throws RemoteException {
|
||||||
|
MediaSessionCompat session = sessionMap.get(sessionTag);
|
||||||
|
session.setExtras(extras);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ import static androidx.media3.test.session.common.CommonConstants.KEY_TRACK_SELE
|
|||||||
import static androidx.media3.test.session.common.CommonConstants.KEY_VIDEO_SIZE;
|
import static androidx.media3.test.session.common.CommonConstants.KEY_VIDEO_SIZE;
|
||||||
import static androidx.media3.test.session.common.CommonConstants.KEY_VOLUME;
|
import static androidx.media3.test.session.common.CommonConstants.KEY_VOLUME;
|
||||||
import static androidx.media3.test.session.common.MediaSessionConstants.KEY_AVAILABLE_SESSION_COMMANDS;
|
import static androidx.media3.test.session.common.MediaSessionConstants.KEY_AVAILABLE_SESSION_COMMANDS;
|
||||||
|
import static androidx.media3.test.session.common.MediaSessionConstants.KEY_CONTROLLER;
|
||||||
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_CONTROLLER_LISTENER_SESSION_REJECTS;
|
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_CONTROLLER_LISTENER_SESSION_REJECTS;
|
||||||
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_GET_SESSION_ACTIVITY;
|
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_GET_SESSION_ACTIVITY;
|
||||||
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_IS_SESSION_COMMAND_AVAILABLE;
|
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_IS_SESSION_COMMAND_AVAILABLE;
|
||||||
@ -427,6 +428,29 @@ public class MediaSessionProviderService extends Service {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSessionExtras(String sessionId, Bundle extras) throws RemoteException {
|
||||||
|
runOnHandler(() -> sessionMap.get(sessionId).setSessionExtras(extras));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSessionExtrasForController(String sessionId, String controllerKey, Bundle extras)
|
||||||
|
throws RemoteException {
|
||||||
|
runOnHandler(
|
||||||
|
() -> {
|
||||||
|
MediaSession mediaSession = sessionMap.get(sessionId);
|
||||||
|
for (ControllerInfo controllerInfo : mediaSession.getConnectedControllers()) {
|
||||||
|
if (controllerInfo
|
||||||
|
.getConnectionHints()
|
||||||
|
.getString(KEY_CONTROLLER, /* defaultValue= */ "")
|
||||||
|
.equals(controllerKey)) {
|
||||||
|
mediaSession.setSessionExtras(controllerInfo, extras);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// MockPlayer methods
|
// MockPlayer methods
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -197,6 +197,14 @@ public class RemoteMediaSession {
|
|||||||
binder.setCustomLayout(sessionId, bundleList);
|
binder.setCustomLayout(sessionId, bundleList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSessionExtras(Bundle extras) throws RemoteException {
|
||||||
|
binder.setSessionExtras(sessionId, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionExtras(String controllerKey, Bundle extras) throws RemoteException {
|
||||||
|
binder.setSessionExtrasForController(sessionId, controllerKey, extras);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// RemoteMockPlayer methods
|
// RemoteMockPlayer methods
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -173,6 +173,10 @@ public class RemoteMediaSessionCompat {
|
|||||||
binder.setCaptioningEnabled(sessionTag, enabled);
|
binder.setCaptioningEnabled(sessionTag, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setExtras(Bundle extras) throws RemoteException {
|
||||||
|
binder.setSessionExtras(sessionTag, extras);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Non-public methods
|
// Non-public methods
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -58,6 +58,11 @@ public final class TestMediaBrowserListener implements MediaBrowser.Listener {
|
|||||||
return delegate.onSetCustomLayout(controller, layout);
|
return delegate.onSetCustomLayout(controller, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExtrasChanged(MediaController controller, Bundle extras) {
|
||||||
|
delegate.onExtrasChanged(controller, extras);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAvailableSessionCommandsChanged(
|
public void onAvailableSessionCommandsChanged(
|
||||||
MediaController controller, SessionCommands commands) {
|
MediaController controller, SessionCommands commands) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user