diff options
| author | 2019-08-06 11:17:16 +0900 | |
|---|---|---|
| committer | 2019-08-22 17:25:07 +0900 | |
| commit | 23b3aaa464f78814e34b3b7b5220eccb433af6ac (patch) | |
| tree | f492348456da5f79e52eafcdef843a6742fc7f97 | |
| parent | 05c94cec637c7701b8b838a11f5455dc2f801de3 (diff) | |
Media: add MediaRouter2.getRoutes()
As with this CL, media apps can get the list of available routes using
MediaRouter2.getRoutes() or MediaRouter2.Callback.onRouteListChanged().
For that MediaRouterService notifies MediaRouter2 of providerinfos.
This CL also clarifies provider info notification logic.
1) When a new client or a new manager is registered, it will be
notified.
2) When a provider info is updated, it will be notified.
onRouteListChanged will be called for a newly registerd callback.
Fixed a bug that MediaRoute2ProviderProxy didn't report state update
when the provider is disonnected.
Test: atest mediaroutertest
Change-Id: I50f5c3cabce80e7fb0a1b5596883c35911d6f122
10 files changed, 283 insertions, 131 deletions
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl index 8d08beb4a72c..6f44d45c0a12 100644 --- a/media/java/android/media/IMediaRoute2ProviderClient.aidl +++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl @@ -22,5 +22,5 @@ import android.media.MediaRoute2ProviderInfo; * @hide */ oneway interface IMediaRoute2ProviderClient { - void notifyProviderInfoUpdated(in MediaRoute2ProviderInfo info); + void updateProviderInfo(in MediaRoute2ProviderInfo info); } diff --git a/media/java/android/media/IMediaRouter2Client.aidl b/media/java/android/media/IMediaRouter2Client.aidl index 774d6a764f32..26184af699db 100644 --- a/media/java/android/media/IMediaRouter2Client.aidl +++ b/media/java/android/media/IMediaRouter2Client.aidl @@ -16,10 +16,12 @@ package android.media; +import android.media.MediaRoute2ProviderInfo; + /** * @hide */ oneway interface IMediaRouter2Client { - void notifyStateChanged(); void notifyRestoreRoute(); + void notifyProviderInfosUpdated(in List<MediaRoute2ProviderInfo> providers); } diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 08266a5a2051..1b713b6ab74b 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -42,7 +42,7 @@ interface IMediaRouterService { void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction); // Methods for media router 2 - void registerClient2AsUser(IMediaRouter2Client client, String packageName, int userId); + void registerClient2(IMediaRouter2Client client, String packageName); void unregisterClient2(IMediaRouter2Client client); void sendControlRequest(IMediaRouter2Client client, in MediaRoute2Info route, in Intent request); /** @@ -54,8 +54,7 @@ interface IMediaRouterService { void selectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route); void setControlCategories(IMediaRouter2Client client, in List<String> categories); - void registerManagerAsUser(IMediaRouter2Manager manager, - String packageName, int userId); + void registerManager(IMediaRouter2Manager manager, String packageName); void unregisterManager(IMediaRouter2Manager manager); /** * Changes the selected route of an application. diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java index b89b0b1a5f02..e8e0f826e6b6 100644 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -98,7 +98,7 @@ public abstract class MediaRoute2ProviderService extends Service { return; } try { - mClient.notifyProviderInfoUpdated(mProviderInfo); + mClient.updateProviderInfo(mProviderInfo); } catch (RemoteException ex) { Log.w(TAG, "Failed to send onProviderInfoUpdated"); } diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index f4dffa28f133..8e29e34caa14 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -16,13 +16,16 @@ package android.media; +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.content.Context; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -58,6 +61,12 @@ public class MediaRouter2 { private Client mClient; private final String mPackageName; + final Handler mHandler; + + List<MediaRoute2ProviderInfo> mProviders = Collections.emptyList(); + volatile List<MediaRoute2Info> mRoutes = Collections.emptyList(); + + MediaRoute2Info mSelectedRoute; /** * Gets an instance of the media router associated with the context. @@ -78,6 +87,7 @@ public class MediaRouter2 { ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); mPackageName = mContext.getPackageName(); //TODO: read control categories from the manifest + mHandler = new Handler(Looper.getMainLooper()); } /** @@ -100,25 +110,10 @@ public class MediaRouter2 { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(callback, "callback must not be null"); + CallbackRecord record; // This is required to prevent adding the same callback twice. synchronized (mCallbackRecords) { - if (mCallbackRecords.size() == 0) { - synchronized (sLock) { - Client client = new Client(); - try { - mMediaRouterService.registerClient2AsUser(client, mPackageName, - UserHandle.myUserId()); - //TODO: We should merge control categories of callbacks. - mMediaRouterService.setControlCategories(client, mControlCategories); - mClient = client; - } catch (RemoteException ex) { - Log.e(TAG, "Unable to register media router.", ex); - } - } - } - final int index = findCallbackRecordIndexLocked(callback); - CallbackRecord record; if (index < 0) { record = new CallbackRecord(callback); mCallbackRecords.add(record); @@ -129,6 +124,20 @@ public class MediaRouter2 { record.mFlags = flags; } + synchronized (sLock) { + if (mClient == null) { + Client client = new Client(); + try { + mMediaRouterService.registerClient2(client, mPackageName); + mMediaRouterService.setControlCategories(client, mControlCategories); + mClient = client; + } catch (RemoteException ex) { + Log.e(TAG, "Unable to register media router.", ex); + } + } + } + record.notifyRoutes(); + //TODO: Update discovery request here. } @@ -172,10 +181,9 @@ public class MediaRouter2 { Objects.requireNonNull(controlCategories, "control categories must not be null"); Client client; - List<String> newControlCategories; + List<String> newControlCategories = new ArrayList<>(controlCategories); synchronized (sLock) { - mControlCategories = new ArrayList<>(controlCategories); - newControlCategories = mControlCategories; + mControlCategories = newControlCategories; client = mClient; } if (client != null) { @@ -185,8 +193,29 @@ public class MediaRouter2 { Log.e(TAG, "Unable to set control categories.", ex); } } + mHandler.sendMessage(obtainMessage(MediaRouter2::refreshAndNotifyRoutes, this)); } + /** + * Gets the list of {@link MediaRoute2Info routes} currently known to the media router. + * + * @return the list of routes that support at least one of the control categories set by + * the application + */ + @NonNull + public List<MediaRoute2Info> getRoutes() { + return mRoutes; + } + + /** + * Gets the currently selected route. + * + * @return the selected route + */ + @NonNull + public MediaRoute2Info getSelectedRoute() { + return mSelectedRoute; + } /** * Selects the specified route. @@ -199,6 +228,7 @@ public class MediaRouter2 { Client client; synchronized (sLock) { + mSelectedRoute = route; client = mClient; } if (client != null) { @@ -247,6 +277,61 @@ public class MediaRouter2 { return -1; } + void onProviderInfosUpdated(List<MediaRoute2ProviderInfo> providers) { + if (providers == null) { + Log.w(TAG, "Providers info is null."); + return; + } + + mProviders = providers; + refreshAndNotifyRoutes(); + } + + void refreshAndNotifyRoutes() { + ArrayList<MediaRoute2Info> routes = new ArrayList<>(); + + List<String> controlCategories; + synchronized (sLock) { + controlCategories = mControlCategories; + } + + for (MediaRoute2ProviderInfo provider : mProviders) { + updateProvider(provider, controlCategories, routes); + } + + //TODO: Can orders be changed? + if (!Objects.equals(mRoutes, routes)) { + mRoutes = Collections.unmodifiableList(routes); + notifyRouteListChanged(mRoutes); + } + } + + void updateProvider(MediaRoute2ProviderInfo provider, List<String> controlCategories, + List<MediaRoute2Info> outRoutes) { + if (provider == null || !provider.isValid()) { + Log.w(TAG, "Ignoring invalid provider : " + provider); + } + + final Collection<MediaRoute2Info> routes = provider.getRoutes(); + for (MediaRoute2Info route : routes) { + if (!route.isValid()) { + Log.w(TAG, "Ignoring invalid route : " + route); + continue; + } + if (!route.supportsControlCategory(controlCategories)) { + continue; + } + outRoutes.add(route); + } + } + + void notifyRouteListChanged(List<MediaRoute2Info> routes) { + for (CallbackRecord record: mCallbackRecords) { + record.mExecutor.execute( + () -> record.mCallback.onRoutesChanged(routes)); + } + } + /** * Interface for receiving events about media routing changes. */ @@ -265,9 +350,14 @@ public class MediaRouter2 { * Called when a route is removed. */ public void onRouteRemoved(MediaRoute2Info routeInfo) {} + + /** + * Called when the list of routes is changed. + */ + public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {} } - static final class CallbackRecord { + final class CallbackRecord { public final Callback mCallback; public Executor mExecutor; public int mFlags; @@ -275,13 +365,25 @@ public class MediaRouter2 { CallbackRecord(@NonNull Callback callback) { mCallback = callback; } + + void notifyRoutes() { + final List<MediaRoute2Info> routes = mRoutes; + // notify only when bound to media router service. + //TODO: Correct the condition when control category, default rotue, .. are finalized. + if (routes.size() > 0) { + mExecutor.execute(() -> mCallback.onRoutesChanged(routes)); + } + } } class Client extends IMediaRouter2Client.Stub { @Override - public void notifyStateChanged() throws RemoteException {} + public void notifyRestoreRoute() throws RemoteException {} @Override - public void notifyRestoreRoute() throws RemoteException {} + public void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> info) { + mHandler.sendMessage(obtainMessage(MediaRouter2::onProviderInfosUpdated, + MediaRouter2.this, info)); + } } } diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 6c53f7d6d73f..0b645691ea3b 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -25,7 +25,6 @@ import android.content.Context; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; @@ -104,26 +103,28 @@ public class MediaRouter2Manager { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(callback, "callback must not be null"); + CallbackRecord callbackRecord; synchronized (mCallbacks) { if (findCallbackRecordIndexLocked(callback) >= 0) { Log.w(TAG, "Ignoring to add the same callback twice."); return; } - synchronized (sLock) { - if (mCallbacks.size() == 0) { - Client client = new Client(); - try { - mMediaRouterService.registerManagerAsUser(client, mPackageName, - UserHandle.myUserId()); - mClient = client; - } catch (RemoteException ex) { - Log.e(TAG, "Unable to register media router manager.", ex); - } + callbackRecord = new CallbackRecord(executor, callback); + mCallbacks.add(callbackRecord); + } + + synchronized (sLock) { + if (mClient == null) { + Client client = new Client(); + try { + mMediaRouterService.registerManager(client, mPackageName); + mClient = client; + } catch (RemoteException ex) { + Log.e(TAG, "Unable to register media router manager.", ex); } + } else { + callbackRecord.notifyRoutes(); } - CallbackRecord record = new CallbackRecord(executor, callback); - mCallbacks.add(record); - record.notifyRoutes(); } } @@ -149,6 +150,7 @@ public class MediaRouter2Manager { } catch (RemoteException ex) { Log.e(TAG, "Unable to unregister media router manager", ex); } + mClient.notifyProviderInfosUpdated(Collections.emptyList()); mClient = null; } } @@ -255,6 +257,10 @@ public class MediaRouter2Manager { final MediaRoute2ProviderInfo prevProvider = mProviders.get(index); final Set<String> updatedRouteIds = new HashSet<>(); for (MediaRoute2Info routeInfo : routes) { + if (!routeInfo.isValid()) { + Log.w(TAG, "Ignoring invalid route : " + routeInfo); + continue; + } final MediaRoute2Info prevRoute = prevProvider.getRoute(routeInfo.getId()); if (prevRoute == null) { notifyRouteAdded(routeInfo); @@ -303,7 +309,7 @@ public class MediaRouter2Manager { void notifyRouteListChanged() { for (CallbackRecord record: mCallbacks) { record.mExecutor.execute( - () -> record.mCallback.onRouteListChanged(mRoutes)); + () -> record.mCallback.onRoutesChanged(mRoutes)); } } @@ -369,10 +375,10 @@ public class MediaRouter2Manager { public void onRouteSelected(@NonNull String packageName, @Nullable MediaRoute2Info route) {} /** - * Called when the list of routes are changed. + * Called when the list of routes is changed. * A client may refresh available routes for each application. */ - public void onRouteListChanged(@NonNull List<MediaRoute2Info> routes) {} + public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {} } final class CallbackRecord { @@ -385,6 +391,7 @@ public class MediaRouter2Manager { } void notifyRoutes() { + mExecutor.execute(() -> mCallback.onRoutesChanged(mRoutes)); for (MediaRoute2Info routeInfo : mRoutes) { mExecutor.execute( () -> mCallback.onRouteAdded(routeInfo)); diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java index 946fb5e0e0ec..3abf0a4941e6 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java @@ -18,6 +18,7 @@ package com.android.mediaroutertest; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; @@ -42,10 +43,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest @@ -96,6 +95,7 @@ public class MediaRouterManagerTest { mPackageName = mContext.getPackageName(); } + //TODO: Move to a seperate file @Test public void testMediaRoute2Info() { MediaRoute2Info routeInfo1 = new MediaRoute2Info.Builder("id", "name") @@ -159,7 +159,7 @@ public class MediaRouterManagerTest { mRouter.unregisterCallback(mockRouterCallback); verify(mockCallback, timeout(TIMEOUT_MS)) - .onRouteListChanged(argThat(routes -> routes.size() > 0)); + .onRoutesChanged(argThat(routes -> routes.size() > 0)); Map<String, MediaRoute2Info> routes = createRouteMap(mManager.getAvailableRoutes(mPackageName)); @@ -170,40 +170,48 @@ public class MediaRouterManagerTest { mManager.unregisterCallback(mockCallback); } + /** + * Tests if we get proper routes for application that has special control category. + */ @Test - public void onRouteSelectedTest() throws Exception { - CountDownLatch latch = new CountDownLatch(1); + public void testGetRoutes() throws Exception { + MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class); + mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL); + mRouter.registerCallback(mExecutor, mockCallback); + verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce()) + .onRoutesChanged(argThat(routes -> routes.size() > 0)); + Map<String, MediaRoute2Info> routes = createRouteMap(mRouter.getRoutes()); + Assert.assertEquals(1, routes.size()); + Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); + + mRouter.unregisterCallback(mockCallback); + } + + @Test + public void testOnRouteSelected() throws Exception { MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class); + MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class); + + mManager.registerCallback(mExecutor, managerCallback); + mRouter.setControlCategories(CONTROL_CATEGORIES_ALL); mRouter.registerCallback(mExecutor, mockRouterCallback); - MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() { - MediaRoute2Info mSelectedRoute = null; - - @Override - public void onRouteAdded(MediaRoute2Info routeInfo) { - if (mSelectedRoute == null) { - mSelectedRoute = routeInfo; - mManager.selectRoute(mPackageName, mSelectedRoute); - } - } - - @Override - public void onRouteSelected(String packageName, MediaRoute2Info route) { - if (TextUtils.equals(packageName, mPackageName) - && mSelectedRoute != null - && route != null - && TextUtils.equals(route.getId(), mSelectedRoute.getId())) { - latch.countDown(); - } - } - }; + verify(managerCallback, timeout(TIMEOUT_MS)) + .onRoutesChanged(argThat(routes -> routes.size() > 0)); - mManager.registerCallback(mExecutor, managerCallback); + Map<String, MediaRoute2Info> routes = + createRouteMap(mManager.getAvailableRoutes(mPackageName)); - Assert.assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1); + mManager.selectRoute(mPackageName, routeToSelect); + + assertNotNull(routeToSelect); + verify(managerCallback, timeout(TIMEOUT_MS)) + .onRouteAdded(argThat(route -> route.equals(routeToSelect))); mManager.unregisterCallback(managerCallback); + mRouter.unregisterCallback(mockRouterCallback); } /** @@ -219,7 +227,7 @@ public class MediaRouterManagerTest { mRouter.registerCallback(mExecutor, routerCallback); verify(managerCallback, timeout(TIMEOUT_MS)) - .onRouteListChanged(argThat(routes -> routes.size() > 0)); + .onRoutesChanged(argThat(routes -> routes.size() > 0)); Map<String, MediaRoute2Info> routes = createRouteMap(mManager.getAvailableRoutes(mPackageName)); @@ -244,7 +252,8 @@ public class MediaRouterManagerTest { mManager.unregisterCallback(managerCallback); } - Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) { + // Helper for getting routes easily + static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) { Map<String, MediaRoute2Info> routeMap = new HashMap<>(); for (MediaRoute2Info route : routes) { routeMap.put(route.getId(), route); diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java index 9e3401882f45..e753a7be99f6 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java @@ -43,7 +43,7 @@ import java.util.Objects; * Maintains a connection to a particular media route provider service. */ final class MediaRoute2ProviderProxy implements ServiceConnection { - private static final String TAG = "MediaRoute2ProviderProxy"; + private static final String TAG = "MediaRoute2Provider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Context mContext; @@ -54,7 +54,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { private Callback mCallback; - //TODO: make it nonnull private MediaRoute2ProviderInfo mProviderInfo; // Connection state @@ -246,13 +245,21 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { if (mActiveConnection != connection) { return; } - // Set a unique provider id for identifying providers. - mProviderInfo = new MediaRoute2ProviderInfo.Builder(info) - .setUniqueId(mUniqueId) - .build(); if (DEBUG) { Slog.d(TAG, this + ": State changed "); } + setAndNotifyProviderInfo(info); + } + + private void setAndNotifyProviderInfo(MediaRoute2ProviderInfo info) { + //TODO: check if info is not updated + if (info == null) { + mProviderInfo = null; + } else { + mProviderInfo = new MediaRoute2ProviderInfo.Builder(info) + .setUniqueId(mUniqueId) + .build(); + } mHandler.post(mStateChanged); } @@ -261,6 +268,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { mConnectionReady = false; mActiveConnection.dispose(); mActiveConnection = null; + setAndNotifyProviderInfo(null); } } @@ -337,7 +345,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { mHandler.post(() -> onConnectionDied(Connection.this)); } - void postProviderUpdated(MediaRoute2ProviderInfo info) { + void postProviderInfoUpdated(MediaRoute2ProviderInfo info) { mHandler.post(() -> onProviderInfoUpdated(Connection.this, info)); } } @@ -354,10 +362,10 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { } @Override - public void notifyProviderInfoUpdated(MediaRoute2ProviderInfo info) { + public void updateProviderInfo(MediaRoute2ProviderInfo info) { Connection connection = mConnectionRef.get(); if (connection != null) { - connection.postProviderUpdated(info); + connection.postProviderInfoUpdated(info); } } } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 12137fe8d841..043c834230d1 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -33,6 +33,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; @@ -72,21 +73,20 @@ class MediaRouter2ServiceImpl { mContext = context; } - public void registerClientAsUser(@NonNull IMediaRouter2Client client, - @NonNull String packageName, int userId) { + public void registerClient(@NonNull IMediaRouter2Client client, + @NonNull String packageName) { Objects.requireNonNull(client, "client must not be null"); final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); - final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, - false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName); + final int userId = UserHandle.getUserId(uid); final boolean trusted = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) == PackageManager.PERMISSION_GRANTED; final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - registerClientLocked(client, uid, pid, packageName, resolvedUserId, trusted); + registerClientLocked(client, uid, pid, packageName, userId, trusted); } } finally { Binder.restoreCallingIdentity(token); @@ -106,20 +106,20 @@ class MediaRouter2ServiceImpl { } } - public void registerManagerAsUser(@NonNull IMediaRouter2Manager manager, - @NonNull String packageName, int userId) { + public void registerManager(@NonNull IMediaRouter2Manager manager, + @NonNull String packageName) { Objects.requireNonNull(manager, "manager must not be null"); //TODO: should check permission final boolean trusted = true; final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); - final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, - false /*allowAll*/, true /*requireFull*/, "registerManagerAsUser", packageName); + final int userId = UserHandle.getUserId(uid); + final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - registerManagerLocked(manager, uid, pid, packageName, resolvedUserId, trusted); + registerManagerLocked(manager, uid, pid, packageName, userId, trusted); } } finally { Binder.restoreCallingIdentity(token); @@ -254,6 +254,10 @@ class MediaRouter2ServiceImpl { userRecord.mClientRecords.add(clientRecord); mAllClientRecords.put(binder, clientRecord); + + userRecord.mHandler.sendMessage( + obtainMessage(UserHandler::notifyProviderInfosUpdatedToClient, + userRecord.mHandler, client)); } } @@ -341,9 +345,9 @@ class MediaRouter2ServiceImpl { userRecord.mManagerRecords.add(managerRecord); mAllManagerRecords.put(binder, managerRecord); - //TODO: remove this when it's unnecessary - // Sends published routes to newly added manager. - userRecord.mHandler.scheduleUpdateManagerState(); + userRecord.mHandler.sendMessage( + obtainMessage(UserHandler::notifyProviderInfosUpdatedToManager, + userRecord.mHandler, manager)); final int count = userRecord.mClientRecords.size(); for (int i = 0; i < count; i++) { @@ -504,14 +508,14 @@ class MediaRouter2ServiceImpl { private final WeakReference<MediaRouter2ServiceImpl> mServiceRef; private final UserRecord mUserRecord; private final MediaRoute2ProviderWatcher mWatcher; - private final ArrayList<IMediaRouter2Manager> mTempManagers = new ArrayList<>(); //TODO: Make this thread-safe. private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders = new ArrayList<>(); + private List<MediaRoute2ProviderInfo> mProviderInfos; private boolean mRunning; - private boolean mManagerStateUpdateScheduled; + private boolean mProviderInfosUpdateScheduled; UserHandler(MediaRouter2ServiceImpl service, UserRecord userRecord) { super(Looper.getMainLooper(), null, true); @@ -553,14 +557,14 @@ class MediaRouter2ServiceImpl { } private void updateProvider(MediaRoute2ProviderProxy provider) { - scheduleUpdateManagerState(); + scheduleUpdateProviderInfos(); } private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) { if (route != null) { MediaRoute2ProviderProxy provider = findProvider(route.getProviderId()); if (provider == null) { - Log.w(TAG, "Ignoring to select route of unknown provider " + route); + Slog.w(TAG, "Ignoring to select route of unknown provider " + route); } else { provider.selectRoute(clientRecord.mPackageName, route.getId()); } @@ -571,7 +575,7 @@ class MediaRouter2ServiceImpl { if (route != null) { MediaRoute2ProviderProxy provider = findProvider(route.getProviderId()); if (provider == null) { - Log.w(TAG, "Ignoring to unselect route of unknown provider " + route); + Slog.w(TAG, "Ignoring to unselect route of unknown provider " + route); } else { provider.unselectRoute(clientRecord.mPackageName, route.getId()); } @@ -585,49 +589,71 @@ class MediaRouter2ServiceImpl { } } - private void scheduleUpdateManagerState() { - if (!mManagerStateUpdateScheduled) { - mManagerStateUpdateScheduled = true; - sendMessage(PooledLambda.obtainMessage(UserHandler::updateManagerState, this)); + private void scheduleUpdateProviderInfos() { + if (!mProviderInfosUpdateScheduled) { + mProviderInfosUpdateScheduled = true; + sendMessage(PooledLambda.obtainMessage(UserHandler::updateProviderInfos, this)); } } - private void updateManagerState() { - mManagerStateUpdateScheduled = false; + private void updateProviderInfos() { + mProviderInfosUpdateScheduled = false; MediaRouter2ServiceImpl service = mServiceRef.get(); if (service == null) { return; } - //TODO: Consider using a member variable (like mTempManagers). + final List<IMediaRouter2Manager> managers = new ArrayList<>(); + final List<IMediaRouter2Client> clients = new ArrayList<>(); final List<MediaRoute2ProviderInfo> providers = new ArrayList<>(); for (MediaRoute2ProviderProxy mediaProvider : mMediaProviders) { final MediaRoute2ProviderInfo providerInfo = mediaProvider.getProviderInfo(); if (providerInfo == null || !providerInfo.isValid()) { - Log.w(TAG, "Ignoring invalid provider info : " + providerInfo); + Slog.w(TAG, "Ignoring invalid provider info : " + providerInfo); } else { providers.add(providerInfo); } } + mProviderInfos = providers; - try { - synchronized (service.mLock) { - final int count = mUserRecord.mManagerRecords.size(); - for (int i = 0; i < count; i++) { - mTempManagers.add(mUserRecord.mManagerRecords.get(i).mManager); - } + synchronized (service.mLock) { + for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) { + managers.add(managerRecord.mManager); } - for (IMediaRouter2Manager tempManager : mTempManagers) { - try { - tempManager.notifyProviderInfosUpdated(providers); - } catch (RemoteException ex) { - Slog.w(TAG, "Failed to update manager state. Manager probably died.", ex); - } + for (ClientRecord clientRecord : mUserRecord.mClientRecords) { + clients.add(clientRecord.mClient); } - } finally { - // Clear the list in preparation for the next time. - mTempManagers.clear(); + } + for (IMediaRouter2Manager manager : managers) { + notifyProviderInfosUpdatedToManager(manager); + } + for (IMediaRouter2Client client : clients) { + notifyProviderInfosUpdatedToClient(client); + } + } + + private void notifyProviderInfosUpdatedToClient(IMediaRouter2Client client) { + if (mProviderInfos == null) { + scheduleUpdateProviderInfos(); + return; + } + try { + client.notifyProviderInfosUpdated(mProviderInfos); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to notify provider infos updated. Client probably died."); + } + } + + private void notifyProviderInfosUpdatedToManager(IMediaRouter2Manager manager) { + if (mProviderInfos == null) { + scheduleUpdateProviderInfos(); + return; + } + try { + manager.notifyProviderInfosUpdated(mProviderInfos); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to notify provider infos updated. Manager probably died."); } } diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index a43068b87c06..2670cd8247ac 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -435,12 +435,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override - public void registerClient2AsUser(IMediaRouter2Client client, String packageName, int userId) { + public void registerClient2(IMediaRouter2Client client, String packageName) { final int uid = Binder.getCallingUid(); if (!validatePackageName(uid, packageName)) { throw new SecurityException("packageName must match the calling uid"); } - mService2.registerClientAsUser(client, packageName, userId); + mService2.registerClient(client, packageName); } // Binder call @@ -464,13 +464,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override - public void registerManagerAsUser(IMediaRouter2Manager manager, - String packageName, int userId) { + public void registerManager(IMediaRouter2Manager manager, String packageName) { final int uid = Binder.getCallingUid(); if (!validatePackageName(uid, packageName)) { throw new SecurityException("packageName must match the calling uid"); } - mService2.registerManagerAsUser(manager, packageName, userId); + mService2.registerManager(manager, packageName); } // Binder call |