diff options
| author | 2020-01-17 09:36:07 +0000 | |
|---|---|---|
| committer | 2020-01-17 09:36:07 +0000 | |
| commit | dda8cdd5102db71ede11ac1d9749e7aaea52238f (patch) | |
| tree | 17ddbfd421f5eeb2d5f38ebd125aee907a66d325 | |
| parent | 42b4cba128be49de390122207ca20925be8f77d5 (diff) | |
| parent | 84e027d63b4a2a2ac339017c364a4075d9f3c360 (diff) | |
Merge "MediaRouter2: Add OnCreateSessionListener"
11 files changed, 178 insertions, 27 deletions
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl index aa38e5148069..a25aff6611ca 100644 --- a/media/java/android/media/IMediaRoute2Provider.aidl +++ b/media/java/android/media/IMediaRoute2Provider.aidl @@ -18,13 +18,15 @@ package android.media; import android.content.Intent; import android.media.IMediaRoute2ProviderClient; +import android.os.Bundle; /** * {@hide} */ oneway interface IMediaRoute2Provider { void setClient(IMediaRoute2ProviderClient client); - void requestCreateSession(String packageName, String routeId, long requestId); + void requestCreateSession(String packageName, String routeId, long requestId, + in @nullable Bundle sessionHints); void releaseSession(String sessionId); void selectRoute(String sessionId, String routeId); diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 2d3e185e967c..5275399bafda 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -24,6 +24,7 @@ import android.media.MediaRoute2Info; import android.media.MediaRouterClientState; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; +import android.os.Bundle; /** * {@hide} @@ -52,7 +53,8 @@ interface IMediaRouterService { void requestSetVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int volume); void requestUpdateVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int direction); - void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route, int requestId); + void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route, int requestId, + in @nullable Bundle sessionHints); void setDiscoveryRequest2(IMediaRouter2Client client, in RouteDiscoveryPreference preference); void selectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route); void deselectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route); diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java index 5a3de6d60277..20ca9979b8f1 100644 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -161,8 +161,8 @@ public abstract class MediaRoute2ProviderService extends Service { * @param sessionInfo information of the new session. * The {@link RoutingSessionInfo#getId() id} of the session must be unique. * @param requestId id of the previous request to create this session provided in - * {@link #onCreateSession(String, String, long)} - * @see #onCreateSession(String, String, long) + * {@link #onCreateSession(String, String, long, Bundle)} + * @see #onCreateSession(String, String, long, Bundle) * @hide */ public final void notifySessionCreated(@NonNull RoutingSessionInfo sessionInfo, @@ -196,8 +196,8 @@ public abstract class MediaRoute2ProviderService extends Service { * Notifies clients of that the session could not be created. * * @param requestId id of the previous request to create the session provided in - * {@link #onCreateSession(String, String, long)}. - * @see #onCreateSession(String, String, long) + * {@link #onCreateSession(String, String, long, Bundle)}. + * @see #onCreateSession(String, String, long, Bundle) * @hide */ public final void notifySessionCreationFailed(long requestId) { @@ -290,6 +290,9 @@ public abstract class MediaRoute2ProviderService extends Service { * @param packageName the package name of the application that selected the route * @param routeId the id of the route initially being connected * @param requestId the id of this session creation request + * @param sessionHints an optional bundle of app-specific arguments sent by + * {@link MediaRouter2}, or null if none. The contents of this bundle + * may affect the result of session creation. * * @see RoutingSessionInfo.Builder#Builder(String, String) * @see RoutingSessionInfo.Builder#addSelectedRoute(String) @@ -297,7 +300,7 @@ public abstract class MediaRoute2ProviderService extends Service { * @hide */ public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId, - long requestId); + long requestId, @Nullable Bundle sessionHints); /** * Called when the session should be released. A client of the session or system can request @@ -432,12 +435,14 @@ public abstract class MediaRoute2ProviderService extends Service { } @Override - public void requestCreateSession(String packageName, String routeId, long requestId) { + public void requestCreateSession(String packageName, String routeId, long requestId, + @Nullable Bundle requestCreateSession) { if (!checkCallerisSystem()) { return; } mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession, - MediaRoute2ProviderService.this, packageName, routeId, requestId)); + MediaRoute2ProviderService.this, packageName, routeId, requestId, + requestCreateSession)); } @Override diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 971b08d17cdb..51d08ec96e6f 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -92,6 +92,7 @@ public class MediaRouter2 { @GuardedBy("sRouterLock") private boolean mShouldUpdateRoutes; private volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList(); + private volatile OnCreateSessionListener mOnCreateSessionListener; /** * Gets an instance of the media router associated with the context. @@ -281,6 +282,19 @@ public class MediaRouter2 { } /** + * Sets an {@link OnCreateSessionListener} to send hints when creating a session. + * To send the hints, listener should be set <em>BEFORE</em> calling + * {@link #requestCreateSession(MediaRoute2Info)}. + * + * @param listener A listener to send optional app-specific hints when creating a session. + * {@code null} for unset. + * @hide + */ + public void setOnCreateSessionListener(@Nullable OnCreateSessionListener listener) { + mOnCreateSessionListener = listener; + } + + /** * Requests the media route provider service to create a session with the given route. * * @param route the route you want to create a session with. @@ -300,13 +314,24 @@ public class MediaRouter2 { SessionCreationRequest request = new SessionCreationRequest(requestId, route); mSessionCreationRequests.add(request); + + OnCreateSessionListener listener = mOnCreateSessionListener; + Bundle sessionHints = null; + if (listener != null) { + sessionHints = listener.onCreateSession(route); + if (sessionHints != null) { + sessionHints = new Bundle(sessionHints); + } + } + Client2 client; synchronized (sRouterLock) { client = mClient; } if (client != null) { try { - mMediaRouterService.requestCreateSession(client, route, requestId); + mMediaRouterService.requestCreateSession(client, route, requestId, + sessionHints); } catch (RemoteException ex) { Log.e(TAG, "Unable to request to create session.", ex); mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler, @@ -707,6 +732,34 @@ public class MediaRouter2 { } /** + * A listener interface to send an optional app-specific hints when creating a session. + * + * @hide + */ + public interface OnCreateSessionListener { + /** + * Called when the {@link MediaRouter2} is about to request + * the media route provider service to create a session with the given route. + * The {@link Bundle} returned here will be sent to media route provider service as a hint + * for creating a session. + * <p> + * To send hints when creating the session, set this listener before calling + * {@link #requestCreateSession(MediaRoute2Info)}. + * <p> + * This will be called on the same thread which calls + * {@link #requestCreateSession(MediaRoute2Info)}. + * + * @param route The route to create session with + * @return An optional bundle of app-specific arguments to send to the provider, + * or null if none. The contents of this bundle may affect the result of + * session creation. + * @see MediaRoute2ProviderService#onCreateSession(String, String, long, Bundle) + */ + @Nullable + Bundle onCreateSession(@NonNull MediaRoute2Info route); + } + + /** * A class to control media routing session in media route provider. * For example, selecting/deselcting/transferring routes to session can be done through this * class. Instances are created by {@link MediaRouter2}. diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java index cc2d1b193970..825b547ea2fa 100644 --- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java +++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java @@ -19,10 +19,12 @@ package com.android.mediarouteprovider.example; import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_SPEAKER; import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV; +import android.annotation.Nullable; import android.content.Intent; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderService; import android.media.RoutingSessionInfo; +import android.os.Bundle; import android.os.IBinder; import android.text.TextUtils; @@ -167,7 +169,8 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService } @Override - public void onCreateSession(String packageName, String routeId, long requestId) { + public void onCreateSession(String packageName, String routeId, long requestId, + @Nullable Bundle sessionHints) { MediaRoute2Info route = mRoutes.get(routeId); if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) { // Tell the router that session cannot be created by passing null as sessionInfo. @@ -188,6 +191,8 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService .addSelectedRoute(routeId) .addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT) .addTransferrableRoute(ROUTE_ID5_TO_TRANSFER_TO) + // Set control hints with given sessionHints + .setControlHints(sessionHints) .build(); notifySessionCreated(sessionInfo, requestId); publishRoutes(); diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java index e782aae7c2d0..32d03db6f7ee 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java @@ -43,12 +43,14 @@ import android.annotation.NonNull; import android.content.Context; import android.media.MediaRoute2Info; import android.media.MediaRouter2; +import android.media.MediaRouter2.OnCreateSessionListener; import android.media.MediaRouter2.RouteCallback; import android.media.MediaRouter2.RoutingController; import android.media.MediaRouter2.SessionCallback; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.net.Uri; +import android.os.Bundle; import android.os.Parcel; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; @@ -80,6 +82,9 @@ public class MediaRouter2Test { private static final int TIMEOUT_MS = 5000; + private static final String TEST_KEY = "test_key"; + private static final String TEST_VALUE = "test_value"; + @Before public void setUp() throws Exception { mContext = InstrumentationRegistry.getTargetContext(); @@ -328,6 +333,74 @@ public class MediaRouter2Test { } @Test + public void testSetOnCreateSessionListener() throws Exception { + final List<String> sampleRouteFeature = new ArrayList<>(); + sampleRouteFeature.add(FEATURE_SAMPLE); + + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteFeature); + MediaRoute2Info route = routes.get(ROUTE_ID1); + assertNotNull(route); + + final Bundle createSessionHints = new Bundle(); + createSessionHints.putString(TEST_KEY, TEST_VALUE); + final OnCreateSessionListener listener = new OnCreateSessionListener() { + @Override + public Bundle onCreateSession(MediaRoute2Info route) { + return createSessionHints; + } + }; + + final CountDownLatch successLatch = new CountDownLatch(1); + final CountDownLatch failureLatch = new CountDownLatch(1); + final List<RoutingController> controllers = new ArrayList<>(); + + // Create session with this route + SessionCallback sessionCallback = new SessionCallback() { + @Override + public void onSessionCreated(RoutingController controller) { + assertNotNull(controller); + assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1)); + + // The SampleMediaRoute2ProviderService supposed to set control hints + // with the given creationSessionHints. + Bundle controlHints = controller.getControlHints(); + assertNotNull(controlHints); + assertTrue(controlHints.containsKey(TEST_KEY)); + assertEquals(TEST_VALUE, controlHints.getString(TEST_KEY)); + + controllers.add(controller); + successLatch.countDown(); + } + + @Override + public void onSessionCreationFailed(MediaRoute2Info requestedRoute) { + failureLatch.countDown(); + } + }; + + // TODO: Remove this once the MediaRouter2 becomes always connected to the service. + RouteCallback routeCallback = new RouteCallback(); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); + + try { + mRouter2.registerSessionCallback(mExecutor, sessionCallback); + + // The SampleMediaRoute2ProviderService supposed to set control hints + // with the given creationSessionHints. + mRouter2.setOnCreateSessionListener(listener); + mRouter2.requestCreateSession(route); + assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + // onSessionCreationFailed should not be called. + assertFalse(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } finally { + releaseControllers(controllers); + mRouter2.unregisterRouteCallback(routeCallback); + mRouter2.unregisterSessionCallback(sessionCallback); + } + } + + @Test public void testSessionCallbackIsNotCalledAfterUnregistered() throws Exception { final List<String> sampleRouteType = new ArrayList<>(); sampleRouteType.add(FEATURE_SAMPLE); diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index b186771031fc..1cd8aad3f0c5 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.Intent; import android.media.MediaRoute2ProviderInfo; import android.media.RoutingSessionInfo; +import android.os.Bundle; import com.android.internal.annotations.GuardedBy; @@ -49,7 +50,8 @@ abstract class MediaRoute2Provider { mCallback = callback; } - public abstract void requestCreateSession(String packageName, String routeId, long requestId); + public abstract void requestCreateSession(String packageName, String routeId, long requestId, + @Nullable Bundle sessionHints); public abstract void releaseSession(String sessionId); public abstract void selectRoute(String sessionId, String routeId); diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java index 4b992be46792..97614619653e 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java @@ -26,6 +26,7 @@ import android.media.IMediaRoute2ProviderClient; import android.media.MediaRoute2ProviderInfo; import android.media.MediaRoute2ProviderService; import android.media.RoutingSessionInfo; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; @@ -73,9 +74,11 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv } @Override - public void requestCreateSession(String packageName, String routeId, long requestId) { + public void requestCreateSession(String packageName, String routeId, long requestId, + Bundle sessionHints) { if (mConnectionReady) { - mActiveConnection.requestCreateSession(packageName, routeId, requestId); + mActiveConnection.requestCreateSession( + packageName, routeId, requestId, sessionHints); updateBinding(); } } @@ -427,9 +430,10 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv mClient.dispose(); } - public void requestCreateSession(String packageName, String routeId, long requestId) { + public void requestCreateSession(String packageName, String routeId, long requestId, + Bundle sessionHints) { try { - mProvider.requestCreateSession(packageName, routeId, requestId); + mProvider.requestCreateSession(packageName, routeId, requestId, sessionHints); } catch (RemoteException ex) { Slog.e(TAG, "Failed to deliver request to create a session.", ex); } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 45d50b33357e..fd8b4f561903 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -22,6 +22,7 @@ import static android.media.MediaRouter2Utils.getProviderId; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -178,14 +179,14 @@ class MediaRouter2ServiceImpl { } public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route, - int requestId) { + int requestId, Bundle sessionHints) { Objects.requireNonNull(client, "client must not be null"); Objects.requireNonNull(route, "route must not be null"); final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - requestCreateSessionLocked(client, route, requestId); + requestCreateSessionLocked(client, route, requestId, sessionHints); } } finally { Binder.restoreCallingIdentity(token); @@ -446,7 +447,7 @@ class MediaRouter2ServiceImpl { } private void requestCreateSessionLocked(@NonNull IMediaRouter2Client client, - @NonNull MediaRoute2Info route, long requestId) { + @NonNull MediaRoute2Info route, long requestId, @Nullable Bundle sessionHints) { final IBinder binder = client.asBinder(); final Client2Record clientRecord = mAllClientRecords.get(binder); @@ -458,7 +459,8 @@ class MediaRouter2ServiceImpl { if (clientRecord != null) { clientRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::requestCreateSessionOnHandler, - clientRecord.mUserRecord.mHandler, clientRecord, route, requestId)); + clientRecord.mUserRecord.mHandler, + clientRecord, route, requestId, sessionHints)); } } @@ -617,9 +619,9 @@ class MediaRouter2ServiceImpl { } long uniqueRequestId = toUniqueRequestId(managerRecord.mClientId, requestId); if (clientRecord != null && managerRecord.mTrusted) { - //TODO: select route feature properly + //TODO: Use client's OnCreateSessionListener to send proper session hints. requestCreateSessionLocked(clientRecord.mClient, route, - uniqueRequestId); + uniqueRequestId, null /* sessionHints */); } } } @@ -980,7 +982,7 @@ class MediaRouter2ServiceImpl { } private void requestCreateSessionOnHandler(Client2Record clientRecord, - MediaRoute2Info route, long requestId) { + MediaRoute2Info route, long requestId, @Nullable Bundle sessionHints) { final MediaRoute2Provider provider = findProvider(route.getProviderId()); if (provider == null) { @@ -996,7 +998,7 @@ class MediaRouter2ServiceImpl { mSessionCreationRequests.add(request); provider.requestCreateSession(clientRecord.mPackageName, route.getOriginalId(), - requestId); + requestId, sessionHints); } private void selectRouteOnHandler(@NonNull Client2Record clientRecord, diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index aad963688cc5..40fca39035f4 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -42,6 +42,7 @@ import android.media.RemoteDisplayState.RemoteDisplayInfo; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -460,8 +461,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route, - int requestId) { - mService2.requestCreateSession(client, route, requestId); + int requestId, Bundle sessionHints) { + mService2.requestCreateSession(client, route, requestId, sessionHints); } // Binder call diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 3759ba9743fa..56c33fe339ea 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -26,6 +26,7 @@ import android.media.IAudioRoutesObserver; import android.media.IAudioService; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; @@ -96,7 +97,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } @Override - public void requestCreateSession(String packageName, String routeId, long requestId) { + public void requestCreateSession(String packageName, String routeId, long requestId, + Bundle sessionHints) { // Do nothing } |