Merge "Use session hints when create a session from MR2Manager" into rvc-dev am: e66ac51ea3
Change-Id: I6b5b7387030050ed3eeb3ec1a039e19ceccf3d44
diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl
index dc06153..a8b82ba 100644
--- a/media/java/android/media/IMediaRouter2.aidl
+++ b/media/java/android/media/IMediaRouter2.aidl
@@ -24,11 +24,15 @@
* @hide
*/
oneway interface IMediaRouter2 {
- void notifyRestoreRoute();
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo);
void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo);
void notifySessionReleased(in RoutingSessionInfo sessionInfo);
+ /**
+ * Gets hints of the new session for the given route.
+ * Call MediaRouterService#notifySessionHintsForCreatingSession to pass the result.
+ */
+ void getSessionHintsForCreatingSession(long uniqueRequestId, in MediaRoute2Info route);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 0d87736..52bac67 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -59,6 +59,8 @@
void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
in MediaRoute2Info route, in @nullable Bundle sessionHints);
+ void notifySessionHintsForCreatingSession(IMediaRouter2 router, long uniqueRequestId,
+ in MediaRoute2Info route, in @nullable Bundle sessionHints);
void selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId,
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index cfe6db9..0ea9624 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -690,6 +690,31 @@
matchingController.releaseInternal(/* shouldReleaseSession= */ false);
}
+ void onGetControllerHintsForCreatingSessionOnHandler(long uniqueRequestId,
+ MediaRoute2Info route) {
+ OnGetControllerHintsListener listener = mOnGetControllerHintsListener;
+ Bundle controllerHints = null;
+ if (listener != null) {
+ controllerHints = listener.onGetControllerHints(route);
+ if (controllerHints != null) {
+ controllerHints = new Bundle(controllerHints);
+ }
+ }
+
+ MediaRouter2Stub stub;
+ synchronized (sRouterLock) {
+ stub = mStub;
+ }
+ if (stub != null) {
+ try {
+ mMediaRouterService.notifySessionHintsForCreatingSession(
+ stub, uniqueRequestId, route, controllerHints);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "getSessionHintsOnHandler: Unable to request.", ex);
+ }
+ }
+ }
+
private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
RouteDiscoveryPreference discoveryRequest) {
return routes.stream()
@@ -820,13 +845,14 @@
*/
public interface OnGetControllerHintsListener {
/**
- * Called when the {@link MediaRouter2} is about to request
- * the media route provider service to create a controller with the given route.
+ * Called when the {@link MediaRouter2} or the system is about to request
+ * a media route provider service to create a controller with the given route.
* The {@link Bundle} returned here will be sent to media route provider service as a hint.
* <p>
- * To send hints when creating the controller, set the listener before calling
- * {@link #transferTo(MediaRoute2Info)}. The method will be called
- * on the same thread which calls {@link #transferTo(MediaRoute2Info)}.
+ * Since controller creation can be requested by the {@link MediaRouter2} and the system,
+ * set the listener as soon as possible after acquiring {@link MediaRouter2} instance.
+ * The method will be called on the same thread that calls
+ * {@link #transferTo(MediaRoute2Info)} or the main thread if it is requested by the system.
*
* @param route The route to create controller with
* @return An optional bundle of app-specific arguments to send to the provider,
@@ -1378,9 +1404,6 @@
class MediaRouter2Stub extends IMediaRouter2.Stub {
@Override
- public void notifyRestoreRoute() throws RemoteException {}
-
- @Override
public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler,
MediaRouter2.this, routes));
@@ -1415,5 +1438,13 @@
mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler,
MediaRouter2.this, sessionInfo));
}
+
+ @Override
+ public void getSessionHintsForCreatingSession(long uniqueRequestId,
+ @NonNull MediaRoute2Info route) {
+ mHandler.sendMessage(obtainMessage(
+ MediaRouter2::onGetControllerHintsForCreatingSessionOnHandler,
+ MediaRouter2.this, uniqueRequestId, route));
+ }
}
}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 207534b..6a1e965 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -48,6 +48,7 @@
import android.media.MediaRouter2Utils;
import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
+import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -74,6 +75,8 @@
private static final String TAG = "MediaRouter2ManagerTest";
private static final int WAIT_TIME_MS = 2000;
private static final int TIMEOUT_MS = 5000;
+ private static final String TEST_KEY = "test_key";
+ private static final String TEST_VALUE = "test_value";
private Context mContext;
private MediaRouter2Manager mManager;
@@ -513,6 +516,56 @@
assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
}
+ @Test
+ public void testRouter2SetOnGetControllerHintsListener() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+ addRouterCallback(new RouteCallback() {});
+
+ MediaRoute2Info route = routes.get(ROUTE_ID1);
+ assertNotNull(route);
+
+ final Bundle controllerHints = new Bundle();
+ controllerHints.putString(TEST_KEY, TEST_VALUE);
+ final CountDownLatch hintLatch = new CountDownLatch(1);
+ final MediaRouter2.OnGetControllerHintsListener listener =
+ route1 -> {
+ hintLatch.countDown();
+ return controllerHints;
+ };
+
+ final CountDownLatch successLatch = new CountDownLatch(1);
+ final CountDownLatch failureLatch = new CountDownLatch(1);
+
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onTransferred(RoutingSessionInfo oldSession,
+ RoutingSessionInfo newSession) {
+ assertTrue(newSession.getSelectedRoutes().contains(route.getId()));
+ // The StubMediaRoute2ProviderService is supposed to set control hints
+ // with the given controllerHints.
+ Bundle controlHints = newSession.getControlHints();
+ assertNotNull(controlHints);
+ assertTrue(controlHints.containsKey(TEST_KEY));
+ assertEquals(TEST_VALUE, controlHints.getString(TEST_KEY));
+
+ successLatch.countDown();
+ }
+
+ @Override
+ public void onTransferFailed(RoutingSessionInfo session,
+ MediaRoute2Info requestedRoute) {
+ failureLatch.countDown();
+ }
+ });
+
+ mRouter2.setOnGetControllerHintsListener(listener);
+ mManager.selectRoute(mPackageName, route);
+ assertTrue(hintLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ assertFalse(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
throws Exception {
CountDownLatch addedLatch = new CountDownLatch(1);
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 0d89997..d8bf9ed 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,8 @@
package com.android.server.media;
+import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
@@ -247,6 +249,22 @@
}
}
+ public void notifySessionHintsForCreatingSession(IMediaRouter2 router,
+ long uniqueRequestId, MediaRoute2Info route, Bundle sessionHints) {
+ Objects.requireNonNull(router, "router must not be null");
+ Objects.requireNonNull(route, "route must not be null");
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ notifySessionHintsForCreatingSessionLocked(uniqueRequestId,
+ router, route, sessionHints);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
MediaRoute2Info route) {
Objects.requireNonNull(router, "router must not be null");
@@ -265,7 +283,6 @@
}
}
-
public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
MediaRoute2Info route) {
Objects.requireNonNull(router, "router must not be null");
@@ -634,12 +651,30 @@
long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
routerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::requestCreateSessionOnHandler,
+ obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler,
routerRecord.mUserRecord.mHandler,
- uniqueRequestId, routerRecord, /* managerRecord= */ null, route,
+ uniqueRequestId, routerRecord, route,
sessionHints));
}
+ private void notifySessionHintsForCreatingSessionLocked(long uniqueRequestId,
+ @NonNull IMediaRouter2 router,
+ @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
+ final IBinder binder = router.asBinder();
+ final RouterRecord routerRecord = mAllRouterRecords.get(binder);
+
+ if (routerRecord == null) {
+ Slog.w(TAG, "requestCreateSessionWithRouter2ByManagerRequestLocked: "
+ + "Ignoring unknown router.");
+ return;
+ }
+
+ routerRecord.mUserRecord.mHandler.sendMessage(
+ obtainMessage(UserHandler::requestCreateSessionWithManagerOnHandler,
+ routerRecord.mUserRecord.mHandler,
+ uniqueRequestId, routerRecord, route, sessionHints));
+ }
+
private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -826,12 +861,13 @@
}
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
- //TODO(b/152851868): Use MediaRouter2's OnCreateSessionListener to send session hints.
+
+ // Before requesting to the provider, get session hints from the media router.
+ // As a return, media router will request to create a session.
routerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::requestCreateSessionOnHandler,
+ obtainMessage(UserHandler::getSessionHintsForCreatingSessionOnHandler,
routerRecord.mUserRecord.mHandler,
- uniqueRequestId, routerRecord, managerRecord, route,
- /* sessionHints= */ null));
+ uniqueRequestId, routerRecord, managerRecord, route));
}
private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
@@ -1149,7 +1185,6 @@
this, provider, uniqueRequestId, sessionInfo));
}
-
@Override
public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo) {
@@ -1267,8 +1302,26 @@
return -1;
}
- private void requestCreateSessionOnHandler(long uniqueRequestId,
- @NonNull RouterRecord routerRecord, @Nullable ManagerRecord managerRecord,
+ private void getSessionHintsForCreatingSessionOnHandler(long uniqueRequestId,
+ @NonNull RouterRecord routerRecord, @NonNull ManagerRecord managerRecord,
+ @NonNull MediaRoute2Info route) {
+ SessionCreationRequest request =
+ new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord);
+ mSessionCreationRequests.add(request);
+
+ try {
+ routerRecord.mRouter.getSessionHintsForCreatingSession(uniqueRequestId, route);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "requestGetSessionHintsOnHandler: "
+ + "Failed to request. Router probably died.");
+ mSessionCreationRequests.remove(request);
+ notifyRequestFailedToManager(managerRecord.mManager,
+ toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
+ }
+ }
+
+ private void requestCreateSessionWithRouter2OnHandler(long uniqueRequestId,
+ @NonNull RouterRecord routerRecord,
@NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
@@ -1281,13 +1334,50 @@
}
SessionCreationRequest request =
- new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord);
+ new SessionCreationRequest(routerRecord, uniqueRequestId, route, null);
mSessionCreationRequests.add(request);
provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
route.getOriginalId(), sessionHints);
}
+ private void requestCreateSessionWithManagerOnHandler(long uniqueRequestId,
+ @NonNull RouterRecord routerRecord,
+ @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
+ SessionCreationRequest matchingRequest = null;
+ for (SessionCreationRequest request : mSessionCreationRequests) {
+ if (request.mUniqueRequestId == uniqueRequestId) {
+ matchingRequest = request;
+ break;
+ }
+ }
+ if (matchingRequest == null) {
+ Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
+ + "Ignoring an unknown request.");
+ return;
+ }
+
+ if (!TextUtils.equals(matchingRequest.mRoute.getId(), route.getId())) {
+ Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
+ + "The given route is different from the requested route.");
+ return;
+ }
+
+ final MediaRoute2Provider provider = findProvider(route.getProviderId());
+ if (provider == null) {
+ Slog.w(TAG, "Ignoring session creation request since no provider found for"
+ + " given route=" + route);
+
+ mSessionCreationRequests.remove(matchingRequest);
+ notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
+ toOriginalRequestId(uniqueRequestId), REASON_ROUTE_NOT_AVAILABLE);
+ return;
+ }
+
+ provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
+ route.getOriginalId(), sessionHints);
+ }
+
// routerRecord can be null if the session is system's or RCN.
private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index d6bf9fb..bf2cc5e 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -487,6 +487,14 @@
// Binder call
@Override
+ public void notifySessionHintsForCreatingSession(IMediaRouter2 router,
+ long uniqueRequestId, MediaRoute2Info route, Bundle sessionHints) {
+ mService2.notifySessionHintsForCreatingSession(router,
+ uniqueRequestId, route, sessionHints);
+ }
+
+ // Binder call
+ @Override
public void selectRouteWithRouter2(IMediaRouter2 router, String sessionId,
MediaRoute2Info route) {
mService2.selectRouteWithRouter2(router, sessionId, route);