Loading media/java/android/media/IMediaRouter2.aidl +5 −1 Original line number Original line Diff line number Diff line Loading @@ -24,11 +24,15 @@ import android.os.Bundle; * @hide * @hide */ */ oneway interface IMediaRouter2 { oneway interface IMediaRouter2 { void notifyRestoreRoute(); void notifyRoutesAdded(in List<MediaRoute2Info> routes); void notifyRoutesAdded(in List<MediaRoute2Info> routes); void notifyRoutesRemoved(in List<MediaRoute2Info> routes); void notifyRoutesRemoved(in List<MediaRoute2Info> routes); void notifyRoutesChanged(in List<MediaRoute2Info> routes); void notifyRoutesChanged(in List<MediaRoute2Info> routes); void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo); void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo); void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo); void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo); void notifySessionReleased(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); } } media/java/android/media/IMediaRouterService.aidl +2 −0 Original line number Original line Diff line number Diff line Loading @@ -59,6 +59,8 @@ interface IMediaRouterService { void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, in MediaRoute2Info route, in @nullable Bundle sessionHints); 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 selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route); void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route); void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route); void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId, void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId, Loading media/java/android/media/MediaRouter2.java +39 −8 Original line number Original line Diff line number Diff line Loading @@ -690,6 +690,31 @@ public final class MediaRouter2 { matchingController.releaseInternal(/* shouldReleaseSession= */ false); 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, private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes, RouteDiscoveryPreference discoveryRequest) { RouteDiscoveryPreference discoveryRequest) { return routes.stream() return routes.stream() Loading Loading @@ -820,13 +845,14 @@ public final class MediaRouter2 { */ */ public interface OnGetControllerHintsListener { public interface OnGetControllerHintsListener { /** /** * Called when the {@link MediaRouter2} is about to request * Called when the {@link MediaRouter2} or the system is about to request * the media route provider service to create a controller with the given route. * 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. * The {@link Bundle} returned here will be sent to media route provider service as a hint. * <p> * <p> * To send hints when creating the controller, set the listener before calling * Since controller creation can be requested by the {@link MediaRouter2} and the system, * {@link #transferTo(MediaRoute2Info)}. The method will be called * set the listener as soon as possible after acquiring {@link MediaRouter2} instance. * on the same thread which calls {@link #transferTo(MediaRoute2Info)}. * 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 * @param route The route to create controller with * @return An optional bundle of app-specific arguments to send to the provider, * @return An optional bundle of app-specific arguments to send to the provider, Loading Loading @@ -1377,9 +1403,6 @@ public final class MediaRouter2 { } } class MediaRouter2Stub extends IMediaRouter2.Stub { class MediaRouter2Stub extends IMediaRouter2.Stub { @Override public void notifyRestoreRoute() throws RemoteException {} @Override @Override public void notifyRoutesAdded(List<MediaRoute2Info> routes) { public void notifyRoutesAdded(List<MediaRoute2Info> routes) { mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler, mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler, Loading Loading @@ -1415,5 +1438,13 @@ public final class MediaRouter2 { mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler, mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler, MediaRouter2.this, sessionInfo)); MediaRouter2.this, sessionInfo)); } } @Override public void getSessionHintsForCreatingSession(long uniqueRequestId, @NonNull MediaRoute2Info route) { mHandler.sendMessage(obtainMessage( MediaRouter2::onGetControllerHintsForCreatingSessionOnHandler, MediaRouter2.this, uniqueRequestId, route)); } } } } } media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java +53 −0 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.media.MediaRouter2Manager; import android.media.MediaRouter2Utils; import android.media.MediaRouter2Utils; import android.media.RouteDiscoveryPreference; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.media.RoutingSessionInfo; import android.os.Bundle; import android.support.test.InstrumentationRegistry; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4; Loading @@ -74,6 +75,8 @@ public class MediaRouter2ManagerTest { private static final String TAG = "MediaRouter2ManagerTest"; private static final String TAG = "MediaRouter2ManagerTest"; private static final int WAIT_TIME_MS = 2000; private static final int WAIT_TIME_MS = 2000; private static final int TIMEOUT_MS = 5000; 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 Context mContext; private MediaRouter2Manager mManager; private MediaRouter2Manager mManager; Loading Loading @@ -513,6 +516,56 @@ public class MediaRouter2ManagerTest { assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax()); 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) Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures) throws Exception { throws Exception { CountDownLatch addedLatch = new CountDownLatch(1); CountDownLatch addedLatch = new CountDownLatch(1); Loading services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +101 −11 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.media; 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.MediaRoute2ProviderService.REQUEST_ID_NONE; import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getProviderId; import static android.media.MediaRouter2Utils.getProviderId; Loading Loading @@ -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, public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, MediaRoute2Info route) { MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(router, "router must not be null"); Loading @@ -265,7 +283,6 @@ class MediaRouter2ServiceImpl { } } } } public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, MediaRoute2Info route) { MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(router, "router must not be null"); Loading Loading @@ -634,12 +651,30 @@ class MediaRouter2ServiceImpl { long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId); long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId); routerRecord.mUserRecord.mHandler.sendMessage( routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::requestCreateSessionOnHandler, obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler, routerRecord.mUserRecord.mHandler, routerRecord.mUserRecord.mHandler, uniqueRequestId, routerRecord, /* managerRecord= */ null, route, uniqueRequestId, routerRecord, route, sessionHints)); 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, private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { final IBinder binder = router.asBinder(); final IBinder binder = router.asBinder(); Loading Loading @@ -826,12 +861,13 @@ class MediaRouter2ServiceImpl { } } long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId); 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( routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::requestCreateSessionOnHandler, obtainMessage(UserHandler::getSessionHintsForCreatingSessionOnHandler, routerRecord.mUserRecord.mHandler, routerRecord.mUserRecord.mHandler, uniqueRequestId, routerRecord, managerRecord, route, uniqueRequestId, routerRecord, managerRecord, route)); /* sessionHints= */ null)); } } private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager, private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager, Loading Loading @@ -1149,7 +1185,6 @@ class MediaRouter2ServiceImpl { this, provider, uniqueRequestId, sessionInfo)); this, provider, uniqueRequestId, sessionInfo)); } } @Override @Override public void onSessionUpdated(@NonNull MediaRoute2Provider provider, public void onSessionUpdated(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo) { @NonNull RoutingSessionInfo sessionInfo) { Loading Loading @@ -1267,8 +1302,26 @@ class MediaRouter2ServiceImpl { return -1; return -1; } } private void requestCreateSessionOnHandler(long uniqueRequestId, private void getSessionHintsForCreatingSessionOnHandler(long uniqueRequestId, @NonNull RouterRecord routerRecord, @Nullable ManagerRecord managerRecord, @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) { @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) { final MediaRoute2Provider provider = findProvider(route.getProviderId()); final MediaRoute2Provider provider = findProvider(route.getProviderId()); Loading @@ -1281,13 +1334,50 @@ class MediaRouter2ServiceImpl { } } SessionCreationRequest request = SessionCreationRequest request = new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord); new SessionCreationRequest(routerRecord, uniqueRequestId, route, null); mSessionCreationRequests.add(request); mSessionCreationRequests.add(request); provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName, provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName, route.getOriginalId(), sessionHints); 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. // routerRecord can be null if the session is system's or RCN. private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord, private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Loading Loading
media/java/android/media/IMediaRouter2.aidl +5 −1 Original line number Original line Diff line number Diff line Loading @@ -24,11 +24,15 @@ import android.os.Bundle; * @hide * @hide */ */ oneway interface IMediaRouter2 { oneway interface IMediaRouter2 { void notifyRestoreRoute(); void notifyRoutesAdded(in List<MediaRoute2Info> routes); void notifyRoutesAdded(in List<MediaRoute2Info> routes); void notifyRoutesRemoved(in List<MediaRoute2Info> routes); void notifyRoutesRemoved(in List<MediaRoute2Info> routes); void notifyRoutesChanged(in List<MediaRoute2Info> routes); void notifyRoutesChanged(in List<MediaRoute2Info> routes); void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo); void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo); void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo); void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo); void notifySessionReleased(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); } }
media/java/android/media/IMediaRouterService.aidl +2 −0 Original line number Original line Diff line number Diff line Loading @@ -59,6 +59,8 @@ interface IMediaRouterService { void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, in MediaRoute2Info route, in @nullable Bundle sessionHints); 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 selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route); void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route); void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route); void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId, void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId, Loading
media/java/android/media/MediaRouter2.java +39 −8 Original line number Original line Diff line number Diff line Loading @@ -690,6 +690,31 @@ public final class MediaRouter2 { matchingController.releaseInternal(/* shouldReleaseSession= */ false); 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, private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes, RouteDiscoveryPreference discoveryRequest) { RouteDiscoveryPreference discoveryRequest) { return routes.stream() return routes.stream() Loading Loading @@ -820,13 +845,14 @@ public final class MediaRouter2 { */ */ public interface OnGetControllerHintsListener { public interface OnGetControllerHintsListener { /** /** * Called when the {@link MediaRouter2} is about to request * Called when the {@link MediaRouter2} or the system is about to request * the media route provider service to create a controller with the given route. * 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. * The {@link Bundle} returned here will be sent to media route provider service as a hint. * <p> * <p> * To send hints when creating the controller, set the listener before calling * Since controller creation can be requested by the {@link MediaRouter2} and the system, * {@link #transferTo(MediaRoute2Info)}. The method will be called * set the listener as soon as possible after acquiring {@link MediaRouter2} instance. * on the same thread which calls {@link #transferTo(MediaRoute2Info)}. * 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 * @param route The route to create controller with * @return An optional bundle of app-specific arguments to send to the provider, * @return An optional bundle of app-specific arguments to send to the provider, Loading Loading @@ -1377,9 +1403,6 @@ public final class MediaRouter2 { } } class MediaRouter2Stub extends IMediaRouter2.Stub { class MediaRouter2Stub extends IMediaRouter2.Stub { @Override public void notifyRestoreRoute() throws RemoteException {} @Override @Override public void notifyRoutesAdded(List<MediaRoute2Info> routes) { public void notifyRoutesAdded(List<MediaRoute2Info> routes) { mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler, mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler, Loading Loading @@ -1415,5 +1438,13 @@ public final class MediaRouter2 { mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler, mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler, MediaRouter2.this, sessionInfo)); MediaRouter2.this, sessionInfo)); } } @Override public void getSessionHintsForCreatingSession(long uniqueRequestId, @NonNull MediaRoute2Info route) { mHandler.sendMessage(obtainMessage( MediaRouter2::onGetControllerHintsForCreatingSessionOnHandler, MediaRouter2.this, uniqueRequestId, route)); } } } } }
media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java +53 −0 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.media.MediaRouter2Manager; import android.media.MediaRouter2Utils; import android.media.MediaRouter2Utils; import android.media.RouteDiscoveryPreference; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.media.RoutingSessionInfo; import android.os.Bundle; import android.support.test.InstrumentationRegistry; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4; Loading @@ -74,6 +75,8 @@ public class MediaRouter2ManagerTest { private static final String TAG = "MediaRouter2ManagerTest"; private static final String TAG = "MediaRouter2ManagerTest"; private static final int WAIT_TIME_MS = 2000; private static final int WAIT_TIME_MS = 2000; private static final int TIMEOUT_MS = 5000; 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 Context mContext; private MediaRouter2Manager mManager; private MediaRouter2Manager mManager; Loading Loading @@ -513,6 +516,56 @@ public class MediaRouter2ManagerTest { assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax()); 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) Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures) throws Exception { throws Exception { CountDownLatch addedLatch = new CountDownLatch(1); CountDownLatch addedLatch = new CountDownLatch(1); Loading
services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +101 −11 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.media; 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.MediaRoute2ProviderService.REQUEST_ID_NONE; import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getProviderId; import static android.media.MediaRouter2Utils.getProviderId; Loading Loading @@ -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, public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, MediaRoute2Info route) { MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(router, "router must not be null"); Loading @@ -265,7 +283,6 @@ class MediaRouter2ServiceImpl { } } } } public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId, MediaRoute2Info route) { MediaRoute2Info route) { Objects.requireNonNull(router, "router must not be null"); Objects.requireNonNull(router, "router must not be null"); Loading Loading @@ -634,12 +651,30 @@ class MediaRouter2ServiceImpl { long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId); long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId); routerRecord.mUserRecord.mHandler.sendMessage( routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::requestCreateSessionOnHandler, obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler, routerRecord.mUserRecord.mHandler, routerRecord.mUserRecord.mHandler, uniqueRequestId, routerRecord, /* managerRecord= */ null, route, uniqueRequestId, routerRecord, route, sessionHints)); 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, private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { final IBinder binder = router.asBinder(); final IBinder binder = router.asBinder(); Loading Loading @@ -826,12 +861,13 @@ class MediaRouter2ServiceImpl { } } long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId); 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( routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::requestCreateSessionOnHandler, obtainMessage(UserHandler::getSessionHintsForCreatingSessionOnHandler, routerRecord.mUserRecord.mHandler, routerRecord.mUserRecord.mHandler, uniqueRequestId, routerRecord, managerRecord, route, uniqueRequestId, routerRecord, managerRecord, route)); /* sessionHints= */ null)); } } private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager, private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager, Loading Loading @@ -1149,7 +1185,6 @@ class MediaRouter2ServiceImpl { this, provider, uniqueRequestId, sessionInfo)); this, provider, uniqueRequestId, sessionInfo)); } } @Override @Override public void onSessionUpdated(@NonNull MediaRoute2Provider provider, public void onSessionUpdated(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo) { @NonNull RoutingSessionInfo sessionInfo) { Loading Loading @@ -1267,8 +1302,26 @@ class MediaRouter2ServiceImpl { return -1; return -1; } } private void requestCreateSessionOnHandler(long uniqueRequestId, private void getSessionHintsForCreatingSessionOnHandler(long uniqueRequestId, @NonNull RouterRecord routerRecord, @Nullable ManagerRecord managerRecord, @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) { @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) { final MediaRoute2Provider provider = findProvider(route.getProviderId()); final MediaRoute2Provider provider = findProvider(route.getProviderId()); Loading @@ -1281,13 +1334,50 @@ class MediaRouter2ServiceImpl { } } SessionCreationRequest request = SessionCreationRequest request = new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord); new SessionCreationRequest(routerRecord, uniqueRequestId, route, null); mSessionCreationRequests.add(request); mSessionCreationRequests.add(request); provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName, provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName, route.getOriginalId(), sessionHints); 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. // routerRecord can be null if the session is system's or RCN. private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord, private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { Loading