Revert "Revert "MediaController2: Enable connecting to the MediaLibraryService2""
This reverts commit b80ea6b45bcb25497a32fcc93594897bd271133a.
Reason for revert: Branch is ready for the merge
Change-Id: If3b629577bc32868438a35ddc2da6cd36cd509cb
diff --git a/media/src/androidTest/java/androidx/media/MediaController2Test.java b/media/src/androidTest/java/androidx/media/MediaController2Test.java
index 3cd7a2a..b8df681 100644
--- a/media/src/androidTest/java/androidx/media/MediaController2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaController2Test.java
@@ -42,6 +42,7 @@
import androidx.annotation.NonNull;
import androidx.media.MediaController2.ControllerCallback;
+import androidx.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
import androidx.media.MediaSession2.ControllerInfo;
import androidx.media.MediaSession2.SessionCallback;
import androidx.media.TestServiceRegistry.SessionServiceCallback;
@@ -1023,7 +1024,6 @@
testConnectToService(MockMediaSessionService2.ID);
}
- @Ignore
@Test
public void testConnectToService_libraryService() throws InterruptedException {
prepareLooper();
@@ -1033,7 +1033,7 @@
public void testConnectToService(String id) throws InterruptedException {
prepareLooper();
final CountDownLatch latch = new CountDownLatch(1);
- final SessionCallback sessionCallback = new SessionCallback() {
+ final MediaLibrarySessionCallback sessionCallback = new MediaLibrarySessionCallback() {
@Override
public SessionCommandGroup2 onConnect(@NonNull MediaSession2 session,
@NonNull ControllerInfo controller) {
diff --git a/media/src/androidTest/java/androidx/media/MockMediaLibraryService2.java b/media/src/androidTest/java/androidx/media/MockMediaLibraryService2.java
index 0c5fd73..8f5d5bb 100644
--- a/media/src/androidTest/java/androidx/media/MockMediaLibraryService2.java
+++ b/media/src/androidTest/java/androidx/media/MockMediaLibraryService2.java
@@ -25,6 +25,7 @@
import androidx.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
import androidx.media.MediaSession2.ControllerInfo;
+import androidx.media.MediaSession2.SessionCallback;
import androidx.media.TestUtils.SyncHandler;
import java.util.ArrayList;
@@ -108,10 +109,12 @@
handler.post(runnable);
}
};
- MediaLibrarySessionCallback librarySessionCallback = (MediaLibrarySessionCallback)
- TestServiceRegistry.getInstance().getSessionCallback();
- if (librarySessionCallback == null) {
- // Use default callback
+ SessionCallback callback = TestServiceRegistry.getInstance().getSessionCallback();
+ MediaLibrarySessionCallback librarySessionCallback;
+ if (callback instanceof MediaLibrarySessionCallback) {
+ librarySessionCallback = (MediaLibrarySessionCallback) callback;
+ } else {
+ // Callback hasn't set. Use default callback
librarySessionCallback = new TestLibrarySessionCallback();
}
mSession = new MediaLibrarySession.Builder(MockMediaLibraryService2.this, executor,
diff --git a/media/src/androidTest/java/androidx/media/TestServiceRegistry.java b/media/src/androidTest/java/androidx/media/TestServiceRegistry.java
index 98a5b89..38286aa 100644
--- a/media/src/androidTest/java/androidx/media/TestServiceRegistry.java
+++ b/media/src/androidTest/java/androidx/media/TestServiceRegistry.java
@@ -21,7 +21,7 @@
import android.os.Handler;
import androidx.annotation.GuardedBy;
-import androidx.media.MediaSession2.SessionCallback;
+import androidx.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
import androidx.media.TestUtils.SyncHandler;
/**
@@ -38,7 +38,7 @@
@GuardedBy("TestServiceRegistry.class")
private SyncHandler mHandler;
@GuardedBy("TestServiceRegistry.class")
- private SessionCallback mSessionCallback;
+ private MediaLibrarySessionCallback mSessionCallback;
@GuardedBy("TestServiceRegistry.class")
private SessionServiceCallback mSessionServiceCallback;
@@ -77,13 +77,13 @@
}
}
- public void setSessionCallback(SessionCallback sessionCallback) {
+ public void setSessionCallback(MediaLibrarySessionCallback sessionCallback) {
synchronized (TestServiceRegistry.class) {
mSessionCallback = sessionCallback;
}
}
- public SessionCallback getSessionCallback() {
+ public MediaLibrarySessionCallback getSessionCallback() {
synchronized (TestServiceRegistry.class) {
return mSessionCallback;
}
diff --git a/media/src/main/java/androidx/media/MediaBrowser2.java b/media/src/main/java/androidx/media/MediaBrowser2.java
index 80b63ff..6ef7fcf 100644
--- a/media/src/main/java/androidx/media/MediaBrowser2.java
+++ b/media/src/main/java/androidx/media/MediaBrowser2.java
@@ -362,12 +362,8 @@
}
private MediaBrowserCompat getBrowserCompat(Bundle extras) {
- if (extras == sDefaultRootHints) {
- return getBrowserCompat();
- } else {
- synchronized (mLock) {
- return mBrowserCompats.get(extras);
- }
+ synchronized (mLock) {
+ return mBrowserCompats.get(extras);
}
}
diff --git a/media/src/main/java/androidx/media/MediaConstants2.java b/media/src/main/java/androidx/media/MediaConstants2.java
index 5de31c0..e9f7d10 100644
--- a/media/src/main/java/androidx/media/MediaConstants2.java
+++ b/media/src/main/java/androidx/media/MediaConstants2.java
@@ -88,6 +88,8 @@
static final String ARGUMENT_PID = "androidx.media.argument.PID";
static final String ARGUMENT_PACKAGE_NAME = "androidx.media.argument.PACKAGE_NAME";
+ static final String ROOT_EXTRA_DEFAULT = "androidx.media.root_default_root";
+
private MediaConstants2() {
}
}
diff --git a/media/src/main/java/androidx/media/MediaController2.java b/media/src/main/java/androidx/media/MediaController2.java
index 40c23ce..71241fa 100644
--- a/media/src/main/java/androidx/media/MediaController2.java
+++ b/media/src/main/java/androidx/media/MediaController2.java
@@ -625,8 +625,12 @@
private static final String TAG = "MediaController2";
private static final boolean DEBUG = true; // TODO(jaewan): Change
- // TODO: Is null root suitable here?
- static final Bundle sDefaultRootHints = null;
+ // Note: Using {@code null} doesn't helpful here because MediaBrowserServiceCompat always wraps
+ // the rootHints so it becomes non-null.
+ static final Bundle sDefaultRootExtras = new Bundle();
+ static {
+ sDefaultRootExtras.putBoolean(MediaConstants2.ROOT_EXTRA_DEFAULT, true);
+ }
private final Context mContext;
private final Object mLock = new Object();
@@ -1613,7 +1617,7 @@
private void connectToService() {
synchronized (mLock) {
mBrowserCompat = new MediaBrowserCompat(mContext, mToken.getComponentName(),
- new ConnectionCallback(), sDefaultRootHints);
+ new ConnectionCallback(), sDefaultRootExtras);
mBrowserCompat.connect();
}
}
diff --git a/media/src/main/java/androidx/media/MediaLibraryService2.java b/media/src/main/java/androidx/media/MediaLibraryService2.java
index 024c1bf..edd97c3 100644
--- a/media/src/main/java/androidx/media/MediaLibraryService2.java
+++ b/media/src/main/java/androidx/media/MediaLibraryService2.java
@@ -36,8 +36,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicReference;
/**
* @hide
@@ -70,6 +70,8 @@
*/
public static final String SERVICE_INTERFACE = "android.media.MediaLibraryService2";
+ // TODO: Revisit this value.
+
/**
* Session for the {@link MediaLibraryService2}. Build this object with
* {@link Builder} and return in {@link #onCreateSession(String)}.
@@ -86,6 +88,9 @@
* to access browse media information before returning the root id; it
* should return null if the client is not allowed to access this
* information.
+ * <p>
+ * Note: this callback may be called on the main thread, regardless of the callback
+ * executor.
*
* @param session the session for this event
* @param controllerInfo information of the controller requesting access to browse
@@ -269,7 +274,6 @@
MediaLibrarySession(SupportLibraryImpl impl) {
super(impl);
-
}
/**
@@ -342,6 +346,11 @@
}
@Override
+ int getSessionType() {
+ return SessionToken2.TYPE_LIBRARY_SERVICE;
+ }
+
+ @Override
public void onCreate() {
super.onCreate();
@@ -476,41 +485,37 @@
}
private class MyBrowserService extends MediaBrowserServiceCompat {
- private final Object mWaitLock = new Object();
-
@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
final Bundle extras) {
+ if (MediaUtils2.isDefaultLibraryRootHint(extras)) {
+ // For connection request from the MediaController2. accept the connection from
+ // here, and let MediaLibrarySession decide whether to accept or reject the
+ // controller.
+ return sDefaultBrowserRoot;
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ // TODO: Revisit this when we support caller information.
final ControllerInfo info = new ControllerInfo(MediaLibraryService2.this, clientUid, -1,
clientPackageName, null);
- final AtomicReference<LibraryRoot> root = new AtomicReference<>();
- synchronized (mWaitLock) {
- // TODO: (Post-P) Fix waiting on the main thread.
- getLibrarySession().getCallbackExecutor().execute(new Runnable() {
- @Override
- public void run() {
- MediaLibrarySession session = getLibrarySession();
- LibraryRoot libraryRoot = session.getCallback().onGetLibraryRoot(
- session, info, extras);
- root.set(libraryRoot);
- mWaitLock.notify();
- }
- });
- while (true) {
- if (root.get() != null) {
- break;
- }
- try {
- mWaitLock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- if (root.get() == null) {
+ MediaLibrarySession session = getLibrarySession();
+ // Call onGetLibraryRoot() directly instead of execute on the executor. Here's the
+ // reason.
+ // We need to return browser root here. So if we run the callback on the executor, we
+ // should wait for the completion.
+ // However, we cannot wait if the callback executor is the main executor, which posts
+ // the runnable to the main thread's. In that case, since this onGetRoot() always runs
+ // on the main thread, the posted runnable for calling onGetLibraryRoot() wouldn't run
+ // in here. Even worse, we cannot know whether it would be run on the main thread or
+ // not.
+ // Because of the reason, just call onGetLibraryRoot directly here. onGetLibraryRoot()
+ // has documentation that it may be called on the main thread.
+ LibraryRoot libraryRoot = session.getCallback().onGetLibraryRoot(
+ session, info, extras);
+ if (libraryRoot == null) {
return null;
}
- return new BrowserRoot(root.get().getRootId(), root.get().getExtras());
+ return new BrowserRoot(libraryRoot.getRootId(), libraryRoot.getExtras());
}
@Override
diff --git a/media/src/main/java/androidx/media/MediaSessionService2.java b/media/src/main/java/androidx/media/MediaSessionService2.java
index 0077efd..7bad65c 100644
--- a/media/src/main/java/androidx/media/MediaSessionService2.java
+++ b/media/src/main/java/androidx/media/MediaSessionService2.java
@@ -32,6 +32,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.media.MediaBrowserServiceCompat.BrowserRoot;
import androidx.media.MediaSession2.ControllerInfo;
import androidx.media.SessionToken2.TokenType;
@@ -128,6 +129,10 @@
*/
public static final String SERVICE_META_DATA = "android.media.session";
+ // Stub BrowserRoot for accepting any connction here.
+ // See MyBrowserService#onGetRoot() for detail.
+ static final BrowserRoot sDefaultBrowserRoot = new BrowserRoot(SERVICE_INTERFACE, null);
+
private final MediaBrowserServiceCompat mBrowserServiceCompat;
private final Object mLock = new Object();
@@ -164,7 +169,8 @@
SessionToken2 token = new SessionToken2(this,
new ComponentName(getPackageName(), getClass().getName()));
if (token.getType() != getSessionType()) {
- throw new RuntimeException("Expected session service, but was " + token.getType());
+ throw new RuntimeException("Expected session type " + getSessionType()
+ + " but was " + token.getType());
}
MediaSession2 session = onCreateSession(token.getId());
synchronized (mLock) {
@@ -312,7 +318,7 @@
// specific operations.
// TODO: Revisit here API not to return stub root here. The fake media ID here may be
// used by the browser service for real.
- return new BrowserRoot(SERVICE_INTERFACE, null);
+ return sDefaultBrowserRoot;
}
@Override
diff --git a/media/src/main/java/androidx/media/MediaUtils2.java b/media/src/main/java/androidx/media/MediaUtils2.java
index e1149bd..657e24d 100644
--- a/media/src/main/java/androidx/media/MediaUtils2.java
+++ b/media/src/main/java/androidx/media/MediaUtils2.java
@@ -424,4 +424,8 @@
}
return MediaPlayerBase.PLAYER_STATE_ERROR;
}
+
+ static boolean isDefaultLibraryRootHint(Bundle bundle) {
+ return bundle != null && bundle.getBoolean(MediaConstants2.ROOT_EXTRA_DEFAULT, false);
+ }
}