diff options
| author | 2019-08-23 04:08:01 +0000 | |
|---|---|---|
| committer | 2019-08-23 04:08:01 +0000 | |
| commit | b958337115e2b4256619d728f7fda30b8beca27b (patch) | |
| tree | ae914e8d94505afd6d84813f86d1ba4c3d1ba682 | |
| parent | 1613d4b92a2419863aa6931cd7cf8316af8ff484 (diff) | |
| parent | 23b3aaa464f78814e34b3b7b5220eccb433af6ac (diff) | |
Merge "Media: add MediaRouter2.getRoutes()"
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 |