diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl index a8b82ba401ebd..ca14052c964fa 100644 --- a/media/java/android/media/IMediaRouter2.aidl +++ b/media/java/android/media/IMediaRouter2.aidl @@ -24,6 +24,8 @@ import android.os.Bundle; * @hide */ oneway interface IMediaRouter2 { + void notifyRouterRegistered(in List currentRoutes, + in RoutingSessionInfo currentSystemSessionInfo); void notifyRoutesAdded(in List routes); void notifyRoutesRemoved(in List routes); void notifyRoutesChanged(in List routes); diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 6634d4b4190ec..20e26cd66e34e 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -92,7 +92,7 @@ public final class MediaRouter2 { MediaRouter2Stub mStub; @GuardedBy("sRouterLock") - private final Map mRoutingControllers = new ArrayMap<>(); + private final Map mNonSystemRoutingControllers = new ArrayMap<>(); private final AtomicInteger mControllerCreationRequestCnt = new AtomicInteger(1); @@ -230,7 +230,7 @@ public final class MediaRouter2 { Log.e(TAG, "unregisterRouteCallback: Unable to set discovery request."); } } - if (mRouteCallbackRecords.size() == 0) { + if (mRouteCallbackRecords.isEmpty() && mNonSystemRoutingControllers.isEmpty()) { try { mMediaRouterService.unregisterRouter2(mStub); } catch (RemoteException ex) { @@ -470,7 +470,7 @@ public final class MediaRouter2 { List result = new ArrayList<>(); result.add(0, mSystemController); synchronized (sRouterLock) { - result.addAll(mRoutingControllers.values()); + result.addAll(mNonSystemRoutingControllers.values()); } return result; } @@ -500,6 +500,77 @@ public final class MediaRouter2 { } } + void syncRoutesOnHandler(List currentRoutes, + RoutingSessionInfo currentSystemSessionInfo) { + if (currentRoutes == null || currentRoutes.isEmpty() || currentSystemSessionInfo == null) { + Log.e(TAG, "syncRoutesOnHandler: Received wrong data. currentRoutes=" + currentRoutes + + ", currentSystemSessionInfo=" + currentSystemSessionInfo); + return; + } + + List addedRoutes = new ArrayList<>(); + List removedRoutes = new ArrayList<>(); + List changedRoutes = new ArrayList<>(); + + synchronized (sRouterLock) { + List currentRoutesIds = currentRoutes.stream().map(MediaRoute2Info::getId) + .collect(Collectors.toList()); + + for (String routeId : mRoutes.keySet()) { + if (!currentRoutesIds.contains(routeId)) { + // This route is removed while the callback is unregistered. + MediaRoute2Info route = mRoutes.get(routeId); + if (route.isSystemRoute() + || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { + removedRoutes.add(mRoutes.get(routeId)); + } + } + } + + for (MediaRoute2Info route : currentRoutes) { + if (mRoutes.containsKey(route.getId())) { + if (!route.equals(mRoutes.get(route.getId()))) { + // This route is changed while the callback is unregistered. + if (route.isSystemRoute() + || route.hasAnyFeatures( + mDiscoveryPreference.getPreferredFeatures())) { + changedRoutes.add(route); + } + } + } else { + // This route is added while the callback is unregistered. + if (route.isSystemRoute() + || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { + addedRoutes.add(route); + } + } + } + + mRoutes.clear(); + for (MediaRoute2Info route : currentRoutes) { + mRoutes.put(route.getId(), route); + } + + mShouldUpdateRoutes = true; + } + + if (addedRoutes.size() > 0) { + notifyRoutesAdded(addedRoutes); + } + if (removedRoutes.size() > 0) { + notifyRoutesRemoved(removedRoutes); + } + if (changedRoutes.size() > 0) { + notifyRoutesChanged(changedRoutes); + } + + RoutingSessionInfo oldInfo = mSystemController.getRoutingSessionInfo(); + mSystemController.setRoutingSessionInfo(currentSystemSessionInfo); + if (!oldInfo.equals(currentSystemSessionInfo)) { + notifyControllerUpdated(mSystemController); + } + } + void addRoutesOnHandler(List routes) { // TODO(b/157874065): When onRoutesAdded is first called, // 1) clear mRoutes before adding the routes @@ -617,7 +688,7 @@ public final class MediaRouter2 { } else { newController = new RoutingController(sessionInfo); synchronized (sRouterLock) { - mRoutingControllers.put(newController.getId(), newController); + mNonSystemRoutingControllers.put(newController.getId(), newController); } } @@ -645,7 +716,7 @@ public final class MediaRouter2 { RoutingController matchingController; synchronized (sRouterLock) { - matchingController = mRoutingControllers.get(sessionInfo.getId()); + matchingController = mNonSystemRoutingControllers.get(sessionInfo.getId()); } if (matchingController == null) { @@ -674,7 +745,7 @@ public final class MediaRouter2 { final String uniqueSessionId = sessionInfo.getId(); RoutingController matchingController; synchronized (sRouterLock) { - matchingController = mRoutingControllers.get(uniqueSessionId); + matchingController = mNonSystemRoutingControllers.get(uniqueSessionId); } if (matchingController == null) { @@ -1232,23 +1303,34 @@ public final class MediaRouter2 { mIsReleased = true; } - MediaRouter2Stub stub; synchronized (sRouterLock) { - mRoutingControllers.remove(getId(), this); - stub = mStub; - } - - if (shouldReleaseSession && stub != null) { - try { - mMediaRouterService.releaseSessionWithRouter2(stub, getId()); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to release session", ex); + if (!mNonSystemRoutingControllers.remove(getId(), this)) { + Log.w(TAG, "releaseInternal: Ignoring unknown controller."); + return false; } - } - if (shouldNotifyStop) { - mHandler.sendMessage(obtainMessage(MediaRouter2::notifyStop, MediaRouter2.this, - RoutingController.this)); + if (shouldReleaseSession && mStub != null) { + try { + mMediaRouterService.releaseSessionWithRouter2(mStub, getId()); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to release session", ex); + } + } + + if (shouldNotifyStop) { + mHandler.sendMessage(obtainMessage(MediaRouter2::notifyStop, MediaRouter2.this, + RoutingController.this)); + } + + if (mRouteCallbackRecords.isEmpty() && mNonSystemRoutingControllers.isEmpty() + && mStub != null) { + try { + mMediaRouterService.unregisterRouter2(mStub); + } catch (RemoteException ex) { + Log.e(TAG, "releaseInternal: Unable to unregister media router.", ex); + } + mStub = null; + } } return true; } @@ -1414,6 +1496,13 @@ public final class MediaRouter2 { } class MediaRouter2Stub extends IMediaRouter2.Stub { + @Override + public void notifyRouterRegistered(List currentRoutes, + RoutingSessionInfo currentSystemSessionInfo) { + mHandler.sendMessage(obtainMessage(MediaRouter2::syncRoutesOnHandler, + MediaRouter2.this, currentRoutes, currentSystemSessionInfo)); + } + @Override public void notifyRoutesAdded(List routes) { mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler, diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 75a89a213052d..0e997155e7af9 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -584,7 +584,7 @@ class MediaRouter2ServiceImpl { mAllRouterRecords.put(binder, routerRecord); userRecord.mHandler.sendMessage( - obtainMessage(UserHandler::notifyRoutesToRouter, + obtainMessage(UserHandler::notifyRouterRegistered, userRecord.mHandler, routerRecord)); } @@ -1769,8 +1769,8 @@ class MediaRouter2ServiceImpl { } } - private void notifyRoutesToRouter(@NonNull RouterRecord routerRecord) { - List routes = new ArrayList<>(); + private void notifyRouterRegistered(@NonNull RouterRecord routerRecord) { + List currentRoutes = new ArrayList<>(); MediaRoute2ProviderInfo systemProviderInfo = null; for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) { @@ -1780,27 +1780,32 @@ class MediaRouter2ServiceImpl { systemProviderInfo = providerInfo; continue; } - routes.addAll(providerInfo.getRoutes()); + currentRoutes.addAll(providerInfo.getRoutes()); } + RoutingSessionInfo currentSystemSessionInfo; if (routerRecord.mHasModifyAudioRoutingPermission) { if (systemProviderInfo != null) { - routes.addAll(systemProviderInfo.getRoutes()); + currentRoutes.addAll(systemProviderInfo.getRoutes()); } else { // This shouldn't happen. Slog.w(TAG, "notifyRoutesToRouter: System route provider not found."); } + currentSystemSessionInfo = mSystemProvider.getSessionInfos().get(0); } else { - routes.add(mSystemProvider.getDefaultRoute()); + currentRoutes.add(mSystemProvider.getDefaultRoute()); + currentSystemSessionInfo = mSystemProvider.getDefaultSessionInfo(); } - if (routes.size() == 0) { + if (currentRoutes.size() == 0) { return; } + try { - routerRecord.mRouter.notifyRoutesAdded(routes); + routerRecord.mRouter.notifyRouterRegistered( + currentRoutes, currentSystemSessionInfo); } catch (RemoteException ex) { - Slog.w(TAG, "Failed to notify all routes. Router probably died.", ex); + Slog.w(TAG, "Failed to notify router registered. Router probably died.", ex); } }