diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaLibraryServiceLegacyStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaLibraryServiceLegacyStub.java index 998c255e28..9a90e9478a 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaLibraryServiceLegacyStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaLibraryServiceLegacyStub.java @@ -317,14 +317,14 @@ import java.util.concurrent.atomic.AtomicReference; } @Override - public ControllerInfo createControllerInfo(RemoteUserInfo remoteUserInfo) { + public ControllerInfo createControllerInfo(RemoteUserInfo remoteUserInfo, Bundle rootHints) { return new ControllerInfo( remoteUserInfo, ControllerInfo.LEGACY_CONTROLLER_VERSION, ControllerInfo.LEGACY_CONTROLLER_INTERFACE_VERSION, getMediaSessionManager().isTrustedForMediaControl(remoteUserInfo), new BrowserLegacyCb(remoteUserInfo), - /* connectionHints= */ Bundle.EMPTY); + /* connectionHints= */ rootHints); } public ControllerCb getBrowserLegacyCbForBroadcast() { diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionServiceLegacyStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionServiceLegacyStub.java index 7cc049ba4b..f845029ed0 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionServiceLegacyStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionServiceLegacyStub.java @@ -61,7 +61,8 @@ import java.util.concurrent.atomic.AtomicReference; public BrowserRoot onGetRoot( String clientPackageName, int clientUid, @Nullable Bundle rootHints) { RemoteUserInfo info = getCurrentBrowserInfo(); - MediaSession.ControllerInfo controller = createControllerInfo(info); + MediaSession.ControllerInfo controller = + createControllerInfo(info, rootHints != null ? rootHints : Bundle.EMPTY); AtomicReference resultReference = new AtomicReference<>(); ConditionVariable haveResult = new ConditionVariable(); @@ -92,14 +93,14 @@ import java.util.concurrent.atomic.AtomicReference; result.sendResult(/* result= */ null); } - public ControllerInfo createControllerInfo(RemoteUserInfo info) { + public ControllerInfo createControllerInfo(RemoteUserInfo info, Bundle rootHints) { return new ControllerInfo( info, ControllerInfo.LEGACY_CONTROLLER_VERSION, ControllerInfo.LEGACY_CONTROLLER_INTERFACE_VERSION, manager.isTrustedForMediaControl(info), /* cb= */ null, - /* connectionHints= */ Bundle.EMPTY); + /* connectionHints= */ rootHints); } public final MediaSessionManager getMediaSessionManager() { diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaLibraryServiceTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaLibraryServiceTest.java index e6b31bd549..b05e2dd455 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaLibraryServiceTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaLibraryServiceTest.java @@ -17,6 +17,7 @@ package androidx.media3.session; import static androidx.media3.session.MediaConstants.EXTRAS_KEY_COMPLETION_STATUS; import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED; +import static androidx.media3.session.MockMediaLibraryService.CONNECTION_HINTS_CUSTOM_LIBRARY_ROOT; import static androidx.media3.test.session.common.CommonConstants.METADATA_ARTWORK_URI; import static androidx.media3.test.session.common.CommonConstants.METADATA_DESCRIPTION; import static androidx.media3.test.session.common.CommonConstants.METADATA_EXTRA_KEY; @@ -93,13 +94,8 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest public void getRoot() throws Exception { // The MockMediaLibraryService gives MediaBrowserConstants.ROOT_ID as root ID, and // MediaBrowserConstants.ROOT_EXTRAS as extras. - handler.postAndSync( - () -> { - browserCompat = - new MediaBrowserCompat( - context, getServiceComponent(), connectionCallback, /* rootHint= */ null); - }); - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); + assertThat(browserCompat.getRoot()).isEqualTo(ROOT_ID); assertThat( browserCompat @@ -113,10 +109,10 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getItem_browsable() throws InterruptedException { + public void getItem_browsable() throws Exception { String mediaId = MEDIA_ID_GET_BROWSABLE_ITEM; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); AtomicReference itemRef = new AtomicReference<>(); browserCompat.getItem( @@ -135,10 +131,10 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getItem_playable() throws InterruptedException { + public void getItem_playable() throws Exception { String mediaId = MEDIA_ID_GET_PLAYABLE_ITEM; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); AtomicReference itemRef = new AtomicReference<>(); browserCompat.getItem( @@ -157,10 +153,10 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getItem_metadata() throws InterruptedException { + public void getItem_metadata() throws Exception { String mediaId = MEDIA_ID_GET_ITEM_WITH_METADATA; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); AtomicReference itemRef = new AtomicReference<>(); browserCompat.getItem( @@ -187,10 +183,10 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getItem_nullResult() throws InterruptedException { + public void getItem_nullResult() throws Exception { String mediaId = "random_media_id"; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.getItem( mediaId, @@ -210,9 +206,9 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getChildren() throws InterruptedException { + public void getChildren() throws Exception { String testParentId = PARENT_ID; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); List receivedChildren = new ArrayList<>(); final String[] receivedParentId = new String[1]; @@ -252,10 +248,10 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getChildren_withLongList() throws InterruptedException { + public void getChildren_withLongList() throws Exception { String testParentId = PARENT_ID_LONG_LIST; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.subscribe( testParentId, @@ -283,14 +279,14 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getChildren_withPagination() throws InterruptedException { + public void getChildren_withPagination() throws Exception { String testParentId = PARENT_ID; int page = 4; int pageSize = 10; Bundle extras = new Bundle(); extras.putString(testParentId, testParentId); - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); Bundle option = new Bundle(); option.putInt(MediaBrowserCompat.EXTRA_PAGE, page); @@ -327,9 +323,9 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getChildren_authErrorResult() throws InterruptedException { + public void getChildren_authErrorResult() throws Exception { String testParentId = PARENT_ID_AUTH_EXPIRED_ERROR; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch errorLatch = new CountDownLatch(1); browserCompat.subscribe( testParentId, @@ -368,10 +364,10 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getChildren_emptyResult() throws InterruptedException { + public void getChildren_emptyResult() throws Exception { String testParentId = PARENT_ID_NO_CHILDREN; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.subscribe( testParentId, @@ -387,10 +383,10 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void getChildren_nullResult() throws InterruptedException { + public void getChildren_nullResult() throws Exception { String testParentId = PARENT_ID_ERROR; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.subscribe( testParentId, @@ -410,7 +406,7 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void search() throws InterruptedException { + public void search() throws Exception { String testQuery = SEARCH_QUERY; int page = 4; int pageSize = 10; @@ -419,7 +415,7 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest testExtras.putInt(MediaBrowserCompat.EXTRA_PAGE, page); testExtras.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize); - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.search( testQuery, @@ -449,7 +445,7 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void search_withLongList() throws InterruptedException { + public void search_withLongList() throws Exception { String testQuery = SEARCH_QUERY_LONG_LIST; int page = 0; int pageSize = Integer.MAX_VALUE; @@ -458,7 +454,7 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest testExtras.putInt(MediaBrowserCompat.EXTRA_PAGE, page); testExtras.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize); - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.search( testQuery, @@ -482,12 +478,12 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void search_emptyResult() throws InterruptedException { + public void search_emptyResult() throws Exception { String testQuery = SEARCH_QUERY_EMPTY_RESULT; Bundle testExtras = new Bundle(); testExtras.putString(testQuery, testQuery); - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.search( testQuery, @@ -506,12 +502,12 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest } @Test - public void search_error() throws InterruptedException { + public void search_error() throws Exception { String testQuery = SEARCH_QUERY_ERROR; Bundle testExtras = new Bundle(); testExtras.putString(testQuery, testQuery); - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.search( testQuery, @@ -534,11 +530,11 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest // TODO: Add test for onCustomCommand() in MediaLibrarySessionLegacyCallbackTest. @Test - public void customAction() throws InterruptedException { + public void customAction() throws Exception { Bundle testArgs = new Bundle(); testArgs.putString("args_key", "args_value"); - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.sendCustomAction( CUSTOM_ACTION, @@ -557,11 +553,11 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest // TODO: Add test for onCustomCommand() in MediaLibrarySessionLegacyCallbackTest. @Test - public void customAction_rejected() throws InterruptedException { + public void customAction_rejected() throws Exception { // This action will not be allowed by the library session. String testAction = "random_custom_action"; - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); CountDownLatch latch = new CountDownLatch(1); browserCompat.sendCustomAction( testAction, @@ -576,4 +572,15 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest .that(latch.await(NO_RESPONSE_TIMEOUT_MS, MILLISECONDS)) .isFalse(); } + + @Test + public void rootBrowserHints_usedAsConnectionHints() throws Exception { + Bundle connectionHints = new Bundle(); + connectionHints.putString(CONNECTION_HINTS_CUSTOM_LIBRARY_ROOT, "myLibraryRoot"); + connectAndWait(connectionHints); + + String root = browserCompat.getRoot(); + + assertThat(root).isEqualTo("myLibraryRoot"); + } } diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaSessionServiceTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaSessionServiceTest.java index 64db577d13..12caed0f8e 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaSessionServiceTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaBrowserCompatWithMediaSessionServiceTest.java @@ -23,6 +23,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import android.content.ComponentName; import android.content.Context; +import android.os.Bundle; import android.support.v4.media.MediaBrowserCompat; import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.PlaybackStateCompat; @@ -63,16 +64,10 @@ public class MediaBrowserCompatWithMediaSessionServiceTest { @Nullable PlaybackStateCompat lastReportedPlaybackStateCompat; @Before - public void setUp() throws Exception { + public void setUp() { context = ApplicationProvider.getApplicationContext(); handler = threadTestRule.getHandler(); connectionCallback = new TestConnectionCallback(); - handler.postAndSync( - () -> { - // Make browser's internal handler to be initialized with test thread. - browserCompat = - new MediaBrowserCompat(context, getServiceComponent(), connectionCallback, null); - }); } @After @@ -87,15 +82,22 @@ public class MediaBrowserCompatWithMediaSessionServiceTest { return MOCK_MEDIA3_SESSION_SERVICE; } - void connectAndWait() throws InterruptedException { + void connectAndWait(Bundle connectionHints) throws Exception { + handler.postAndSync( + () -> { + // Make browser's internal handler to be initialized with test thread. + browserCompat = + new MediaBrowserCompat( + context, getServiceComponent(), connectionCallback, connectionHints); + }); browserCompat.connect(); assertThat(connectionCallback.connectedLatch.await(SERVICE_CONNECTION_TIMEOUT_MS, MILLISECONDS)) .isTrue(); } @Test - public void connect() throws InterruptedException { - connectAndWait(); + public void connect() throws Exception { + connectAndWait(/* connectionHints= */ Bundle.EMPTY); assertThat(connectionCallback.failedLatch.getCount()).isNotEqualTo(0); } @@ -109,7 +111,7 @@ public class MediaBrowserCompatWithMediaSessionServiceTest { @Test public void getSessionToken() throws Exception { - connectAndWait(); + connectAndWait(/* connectionHints= */ Bundle.EMPTY); MediaControllerCompat controller = new MediaControllerCompat(context, browserCompat.getSessionToken()); assertThat(controller.getPackageName()) diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MockMediaLibraryService.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MockMediaLibraryService.java index 0749077056..995b162150 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MockMediaLibraryService.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MockMediaLibraryService.java @@ -82,6 +82,9 @@ public class MockMediaLibraryService extends MediaLibraryService { /** ID of the session that this service will create. */ public static final String ID = "TestLibrary"; + public static final String CONNECTION_HINTS_CUSTOM_LIBRARY_ROOT = + "CONNECTION_HINTS_CUSTOM_LIBRARY_ROOT"; + public static final MediaItem ROOT_ITEM = new MediaItem.Builder() .setMediaId(ROOT_ID) @@ -192,7 +195,24 @@ public class MockMediaLibraryService extends MediaLibraryService { public ListenableFuture> onGetLibraryRoot( MediaLibrarySession session, ControllerInfo browser, @Nullable LibraryParams params) { assertLibraryParams(params); - return Futures.immediateFuture(LibraryResult.ofItem(ROOT_ITEM, ROOT_PARAMS)); + MediaItem rootItem = ROOT_ITEM; + // Use connection hints to select the library root. + String customLibraryRoot = + browser + .getConnectionHints() + .getString(CONNECTION_HINTS_CUSTOM_LIBRARY_ROOT, /* defaultValue= */ null); + if (customLibraryRoot != null) { + rootItem = + new MediaItem.Builder() + .setMediaId(customLibraryRoot) + .setMediaMetadata( + new MediaMetadata.Builder() + .setFolderType(MediaMetadata.FOLDER_TYPE_ALBUMS) + .setIsPlayable(false) + .build()) + .build(); + } + return Futures.immediateFuture(LibraryResult.ofItem(rootItem, ROOT_PARAMS)); } @Override