diff options
| author | 2020-04-14 19:56:16 +0900 | |
|---|---|---|
| committer | 2020-04-21 14:17:08 +0900 | |
| commit | f0eb51bc40e50a9b604417b3ba58334a05ad1b25 (patch) | |
| tree | 71ade330e7147aee75ac3923c130747400eb9a58 | |
| parent | 9c5a02c269f63b1a331be6ec07747ed8ef608c10 (diff) | |
Use session hints when create a session from MR2Manager
When MR2Manager requests to create a routing session, it should pass
session hints to the target provider.
This CL adds a logic that MR2Manager asks media router instance to
get session hints to be passed to the provider.
Bug: 152851868
Test: atest mediaroutertest
Change-Id: Ib421f61f663090c6ed95c8b1a2f7deeb80e5be16
6 files changed, 208 insertions, 20 deletions
diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl index dc06153ffa9f..a8b82ba401eb 100644 --- a/media/java/android/media/IMediaRouter2.aidl +++ b/media/java/android/media/IMediaRouter2.aidl @@ -24,11 +24,15 @@ import android.os.Bundle; * @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 0d87736cfd47..52bac671cc6f 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -59,6 +59,8 @@ interface IMediaRouterService { 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 bd8fb9602656..114d53d6336d 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -690,6 +690,31 @@ public final class MediaRouter2 { 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 final class MediaRouter2 { */ 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 @@ public final class MediaRouter2 { 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 @@ public final class MediaRouter2 { 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 6ca564fb34cc..49a8ce9a18fb 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java @@ -47,6 +47,7 @@ import android.media.MediaRouter2Manager; 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; @@ -73,6 +74,8 @@ public class MediaRouter2ManagerTest { 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; @@ -465,6 +468,56 @@ public class MediaRouter2ManagerTest { 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 0d899974cf93..d8bf9edee2b7 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 @@ class MediaRouter2ServiceImpl { } } + 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 @@ class MediaRouter2ServiceImpl { } } - public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); @@ -634,12 +651,30 @@ class MediaRouter2ServiceImpl { 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 @@ class MediaRouter2ServiceImpl { } 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 @@ class MediaRouter2ServiceImpl { this, provider, uniqueRequestId, sessionInfo)); } - @Override public void onSessionUpdated(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo) { @@ -1267,8 +1302,26 @@ class MediaRouter2ServiceImpl { 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 @@ class MediaRouter2ServiceImpl { } 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 d6bf9fb4d9b5..bf2cc5e68fac 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 @@ public final class MediaRouterService extends IMediaRouterService.Stub // 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); |