diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2018-08-30 06:54:41 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-08-30 06:54:41 +0000 |
commit | fa5ef35a700fd3ab2df2b6514572fe71cb66f78d (patch) | |
tree | 4272051135cb4211eae9991dcacc1c584209555b /mediarouter | |
parent | 60d4217c3d479d7e6c838971038fdf66fe03ee6e (diff) | |
parent | 07f617e626b33f51f7b79fd28b5e90d2619d03b0 (diff) | |
download | support-fa5ef35a700fd3ab2df2b6514572fe71cb66f78d.tar.gz |
Merge "MediaRouter: Support dynmaic group routes." into androidx-master-dev
Diffstat (limited to 'mediarouter')
5 files changed, 309 insertions, 162 deletions
diff --git a/mediarouter/api/current.txt b/mediarouter/api/current.txt index 994a33e33e2..8648a95431f 100644 --- a/mediarouter/api/current.txt +++ b/mediarouter/api/current.txt @@ -271,7 +271,7 @@ package androidx.mediarouter.media { } public static abstract interface MediaRouteProvider.DynamicGroupRouteController.OnDynamicRoutesChangedListener { - method public abstract void onRoutesChanged(java.util.Collection<androidx.mediarouter.media.MediaRouteProvider.DynamicGroupRouteController.DynamicRouteDescriptor>); + method public abstract void onRoutesChanged(androidx.mediarouter.media.MediaRouteProvider.DynamicGroupRouteController, java.util.Collection<androidx.mediarouter.media.MediaRouteProvider.DynamicGroupRouteController.DynamicRouteDescriptor>); } public static final class MediaRouteProvider.ProviderMetadata { @@ -419,7 +419,7 @@ package androidx.mediarouter.media { method public int getVolumeHandling(); method public int getVolumeMax(); method public boolean isBluetooth(); - method public boolean isConnecting(); + method public deprecated boolean isConnecting(); method public boolean isDefault(); method public boolean isDeviceSpeaker(); method public boolean isEnabled(); diff --git a/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteButton.java b/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteButton.java index cc40f72ad06..38d472df643 100644 --- a/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteButton.java +++ b/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteButton.java @@ -488,7 +488,8 @@ public class MediaRouteButton extends View { void refreshRoute() { final MediaRouter.RouteInfo route = mRouter.getSelectedRoute(); final boolean isRemote = !route.isDefaultOrBluetooth() && route.matchesSelector(mSelector); - final boolean isConnecting = isRemote && route.isConnecting(); + final boolean isConnecting = isRemote + && route.getConnectionState() == MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING; boolean needsRefresh = false; if (mRemoteActive != isRemote) { mRemoteActive = isRemote; diff --git a/mediarouter/src/main/java/androidx/mediarouter/media/MainHandlerExecutor.java b/mediarouter/src/main/java/androidx/mediarouter/media/MainHandlerExecutor.java new file mode 100644 index 00000000000..c5d658ad36a --- /dev/null +++ b/mediarouter/src/main/java/androidx/mediarouter/media/MainHandlerExecutor.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.mediarouter.media; + +import android.content.Context; +import android.os.Build; +import android.os.Handler; + +import androidx.annotation.NonNull; + +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +class MainHandlerExecutor implements Executor { + static Executor getExecutor(Context context) { + if (Build.VERSION.SDK_INT >= 28) { + return context.getMainExecutor(); + } + return new MainHandlerExecutor(new Handler(context.getMainLooper())); + } + + private final Handler mHandler; + + MainHandlerExecutor(@NonNull Handler handler) { + mHandler = handler; + } + + @Override + public void execute(Runnable command) { + if (!mHandler.post(command)) { + throw new RejectedExecutionException(mHandler + " is shutting down"); + } + } +} diff --git a/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProvider.java b/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProvider.java index 31ab37349d2..6a5253c2a39 100644 --- a/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProvider.java +++ b/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProvider.java @@ -516,11 +516,14 @@ public abstract class MediaRouteProvider { */ public interface OnDynamicRoutesChangedListener { /** + * @param controller the {@link DynamicGroupRouteController} which keeps this listener. * @param routes the collection of routes contains selected routes * (can be unselectable or not) * and unselected routes (can be groupable or transferable or not). */ - void onRoutesChanged(Collection<DynamicRouteDescriptor> routes); + void onRoutesChanged( + DynamicGroupRouteController controller, + Collection<DynamicRouteDescriptor> routes); } /** diff --git a/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java b/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java index 1ae14108950..0d4c981dbb8 100644 --- a/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java +++ b/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java @@ -50,6 +50,9 @@ import androidx.media2.MediaPlayerConnector; import androidx.media2.MediaPlaylistAgent; import androidx.media2.MediaSession2; import androidx.mediarouter.app.MediaRouteDiscoveryFragment; +import androidx.mediarouter.media.MediaRouteProvider.DynamicGroupRouteController; +import androidx.mediarouter.media.MediaRouteProvider.DynamicGroupRouteController + .DynamicRouteDescriptor; import androidx.mediarouter.media.MediaRouteProvider.ProviderMetadata; import androidx.mediarouter.media.MediaRouteProvider.RouteController; @@ -57,6 +60,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -301,6 +305,11 @@ public final class MediaRouter { return sGlobal.getRoute(uniqueId); } + @Nullable RouteInfo getRoute(String uniqueId) { + checkCallingThread(); + return sGlobal.getRoute(uniqueId); + } + /** * Gets information about the {@link MediaRouter.ProviderInfo route providers} * currently known to this media router. @@ -839,13 +848,12 @@ public final class MediaRouter { private String mDescription; private Uri mIconUri; boolean mEnabled; - private boolean mConnecting; - private int mConnectionState; + private @ConnectionState int mConnectionState; private boolean mCanDisconnect; private final ArrayList<IntentFilter> mControlFilters = new ArrayList<>(); private int mPlaybackType; private int mPlaybackStream; - private int mDeviceType; + private @DeviceType int mDeviceType; private int mVolumeHandling; private int mVolume; private int mVolumeMax; @@ -1061,9 +1069,11 @@ public final class MediaRouter { * yet ready for use. * * @return True if this route is in the process of connecting. + * @deprecated use {@link #getConnectionState} instead. */ + @Deprecated public boolean isConnecting() { - return mConnecting; + return mConnectionState == CONNECTION_STATE_CONNECTING; } /** @@ -1512,7 +1522,6 @@ public final class MediaRouter { + ", description=" + mDescription + ", iconUri=" + mIconUri + ", enabled=" + mEnabled - + ", connecting=" + mConnecting + ", connectionState=" + mConnectionState + ", canDisconnect=" + mCanDisconnect + ", playbackType=" + mPlaybackType @@ -1556,10 +1565,6 @@ public final class MediaRouter { mEnabled = descriptor.isEnabled(); changes |= CHANGE_GENERAL; } - if (mConnecting != descriptor.isConnecting()) { - mConnecting = descriptor.isConnecting(); - changes |= CHANGE_GENERAL; - } if (mConnectionState != descriptor.getConnectionState()) { mConnectionState = descriptor.getConnectionState(); changes |= CHANGE_GENERAL; @@ -1631,30 +1636,13 @@ public final class MediaRouter { */ @RestrictTo(LIBRARY_GROUP) public static class RouteGroup extends RouteInfo { - private List<RouteInfo> mRoutes = new ArrayList<>(); + protected List<RouteInfo> mRoutes = new ArrayList<>(); RouteGroup(ProviderInfo provider, String descriptorId, String uniqueId) { super(provider, descriptorId, uniqueId); } /** - * @return The number of routes in this group - */ - public int getRouteCount() { - return mRoutes.size(); - } - - /** - * Returns the route in this group at the specified index - * - * @param index Index to fetch - * @return The route at index - */ - public RouteInfo getRouteAt(int index) { - return mRoutes.get(index); - } - - /** * Returns the routes in this group * * @return The list of the routes in this group @@ -1710,6 +1698,78 @@ public final class MediaRouter { } /** + * Information about a route that consists of multiple other routes in a group. + * @hide + */ + @RestrictTo(LIBRARY_GROUP) + public static class DynamicGroupInfo extends RouteGroup { + private List<String> mMemberRoutes = new ArrayList<>(); + private List<String> mUnselectableRoutes = new ArrayList<>(); + private List<String> mGroupableRoutes = new ArrayList<>(); + private List<String> mTransferableRoutes = new ArrayList<>(); + + DynamicGroupInfo(ProviderInfo provider, String descriptorId, String uniqueId) { + super(provider, descriptorId, uniqueId); + } + + void updateDescriptors( + Collection<DynamicRouteDescriptor> dynamicDescriptors) { + mMemberRoutes.clear(); + mUnselectableRoutes.clear(); + mGroupableRoutes.clear(); + mTransferableRoutes.clear(); + + for (DynamicRouteDescriptor dynamicDescriptor : + dynamicDescriptors) { + if (dynamicDescriptor.isGroupable()) { + RouteInfo route = findRouteByDynamicRouteDescriptor(dynamicDescriptor); + if (route != null) { + mGroupableRoutes.add(route.getId()); + } + } + if (dynamicDescriptor.isTransferable()) { + RouteInfo route = findRouteByDynamicRouteDescriptor(dynamicDescriptor); + if (route != null) { + mTransferableRoutes.add(route.getId()); + } + } + if ((dynamicDescriptor.getSelectionState() == DynamicRouteDescriptor.SELECTING) + || (dynamicDescriptor.getSelectionState() + == DynamicRouteDescriptor.SELECTED)) { + RouteInfo route = findRouteByDynamicRouteDescriptor(dynamicDescriptor); + if (route != null) { + mMemberRoutes.add(route.getId()); + if (dynamicDescriptor.isUnselectable()) { + mUnselectableRoutes.add(route.getId()); + } + } + } + } + } + + public List<String> getMemberRoutes() { + return mMemberRoutes; + } + + public List<String> getUnselectableRoutes() { + return mUnselectableRoutes; + } + + public List<String> getGroupableRoutes() { + return mGroupableRoutes; + } + + public List<String> getTransferableRoutes() { + return mTransferableRoutes; + } + + RouteInfo findRouteByDynamicRouteDescriptor(DynamicRouteDescriptor dynamicDescriptor) { + String descriptorId = dynamicDescriptor.getRouteDescriptor().getId(); + return getProvider().findRouteByDescriptorId(descriptorId); + } + } + + /** * Provides information about a media route provider. * <p> * This object may be used to determine which media route provider has @@ -1783,7 +1843,7 @@ public final class MediaRouter { return false; } - int findRouteByDescriptorId(String id) { + int findRouteIndexByDescriptorId(String id) { final int count = mRoutes.size(); for (int i = 0; i < count; i++) { if (mRoutes.get(i).mDescriptorId.equals(id)) { @@ -1793,6 +1853,20 @@ public final class MediaRouter { return -1; } + RouteInfo findRouteByDescriptorId(String id) { + final int count = mRoutes.size(); + for (int i = 0; i < count; i++) { + if (mRoutes.get(i).mDescriptorId.equals(id)) { + return mRoutes.get(i); + } + } + return null; + } + + boolean supportsDynamicGroup() { + return mDescriptor != null && mDescriptor.supportsDynamicGroupRoute(); + } + @Override public String toString() { return "MediaRouter.RouteProviderInfo{ packageName=" + getPackageName() @@ -2006,8 +2080,8 @@ public final class MediaRouter { private RouteInfo mDefaultRoute; private RouteInfo mBluetoothRoute; RouteInfo mSelectedRoute; - private RouteController mSelectedRouteController; - // A map from route descriptor ID to RouteController for the member routes in the currently + RouteController mSelectedRouteController; + // A map from unique route ID to RouteController for the member routes in the currently // selected route group. private final Map<String, RouteController> mRouteControllerMap = new HashMap<>(); private MediaRouteDiscoveryRequest mDiscoveryRequest; @@ -2102,7 +2176,7 @@ public final class MediaRouter { if (route == mSelectedRoute && mSelectedRouteController != null) { mSelectedRouteController.onSetVolume(volume); } else if (!mRouteControllerMap.isEmpty()) { - RouteController controller = mRouteControllerMap.get(route.mDescriptorId); + RouteController controller = mRouteControllerMap.get(route.mUniqueId); if (controller != null) { controller.onSetVolume(volume); } @@ -2267,8 +2341,7 @@ public final class MediaRouter { @Override public void addProvider(MediaRouteProvider providerInstance) { - int index = findProviderInfo(providerInstance); - if (index < 0) { + if (findProviderInfo(providerInstance) == null) { // 1. Add the provider to the list. ProviderInfo provider = new ProviderInfo(providerInstance); mProviders.add(provider); @@ -2287,167 +2360,158 @@ public final class MediaRouter { @Override public void removeProvider(MediaRouteProvider providerInstance) { - int index = findProviderInfo(providerInstance); - if (index >= 0) { + ProviderInfo provider = findProviderInfo(providerInstance); + if (provider != null) { // 1. Unregister the provider callback. providerInstance.setCallback(null); // 2. Clear the discovery request. providerInstance.setDiscoveryRequest(null); // 3. Delete the provider's contents. - ProviderInfo provider = mProviders.get(index); updateProviderContents(provider, null); // 4. Remove the provider from the list. if (DEBUG) { Log.d(TAG, "Provider removed: " + provider); } mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_REMOVED, provider); - mProviders.remove(index); + mProviders.remove(provider); } } void updateProviderDescriptor(MediaRouteProvider providerInstance, MediaRouteProviderDescriptor descriptor) { - int index = findProviderInfo(providerInstance); - if (index >= 0) { + ProviderInfo provider = findProviderInfo(providerInstance); + if (provider != null) { // Update the provider's contents. - ProviderInfo provider = mProviders.get(index); updateProviderContents(provider, descriptor); } } - private int findProviderInfo(MediaRouteProvider providerInstance) { + private ProviderInfo findProviderInfo(MediaRouteProvider providerInstance) { final int count = mProviders.size(); for (int i = 0; i < count; i++) { if (mProviders.get(i).mProviderInstance == providerInstance) { - return i; + return mProviders.get(i); } } - return -1; + return null; } private void updateProviderContents(ProviderInfo provider, MediaRouteProviderDescriptor providerDescriptor) { - if (provider.updateDescriptor(providerDescriptor)) { - // Update all existing routes and reorder them to match - // the order of their descriptors. - int targetIndex = 0; - boolean selectedRouteDescriptorChanged = false; - if (providerDescriptor != null) { - if (providerDescriptor.isValid()) { - final List<MediaRouteDescriptor> routeDescriptors = - providerDescriptor.getRoutes(); - final int routeCount = routeDescriptors.size(); - // Updating route group's contents requires all member routes' information. - // Add the groups to the lists and update them later. - List<Pair<RouteInfo, MediaRouteDescriptor>> addedGroups = new ArrayList<>(); - List<Pair<RouteInfo, MediaRouteDescriptor>> updatedGroups = - new ArrayList<>(); - for (int i = 0; i < routeCount; i++) { - final MediaRouteDescriptor routeDescriptor = routeDescriptors.get(i); - final String id = routeDescriptor.getId(); - final int sourceIndex = provider.findRouteByDescriptorId(id); - boolean isGroup = routeDescriptor.getGroupMemberIds() != null; - if (sourceIndex < 0) { - // 1. Add the route to the list. - String uniqueId = assignRouteUniqueId(provider, id); - RouteInfo route = isGroup ? new RouteGroup(provider, id, uniqueId) : - new RouteInfo(provider, id, uniqueId); - provider.mRoutes.add(targetIndex++, route); - mRoutes.add(route); - // 2. Create the route's contents. - if (isGroup) { - addedGroups.add(new Pair<>(route, routeDescriptor)); - } else { - route.maybeUpdateDescriptor(routeDescriptor); - // 3. Notify clients about addition. - if (DEBUG) { - Log.d(TAG, "Route added: " + route); - } - mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route); - } - - } else if (sourceIndex < targetIndex) { - Log.w(TAG, "Ignoring route descriptor with duplicate id: " - + routeDescriptor); - } else { - RouteInfo route = provider.mRoutes.get(sourceIndex); - // 1. Replace route if a group route becomes a normal route - // or vice versa. - if ((route instanceof RouteGroup) != isGroup) { - route = isGroup ? new RouteGroup(provider, id, route.getId()) : - new RouteInfo(provider, id, route.getId()); - provider.mRoutes.set(sourceIndex, route); - } - // 2. Reorder the route within the list. - Collections.swap(provider.mRoutes, - sourceIndex, targetIndex++); - // 3. Update the route's contents. - if (route instanceof RouteGroup) { - updatedGroups.add(new Pair<>(route, routeDescriptor)); - } else { - // 4. Notify clients about changes. - if (updateRouteDescriptorAndNotify(route, routeDescriptor) - != 0) { - if (route == mSelectedRoute) { - selectedRouteDescriptorChanged = true; - } - } - } - } - } - // Update the new and/or existing groups. - for (Pair<RouteInfo, MediaRouteDescriptor> pair : addedGroups) { - RouteInfo route = pair.first; - route.maybeUpdateDescriptor(pair.second); + if (!provider.updateDescriptor(providerDescriptor)) { + // Nothing to update. + return; + } + // Update all existing routes and reorder them to match + // the order of their descriptors. + int targetIndex = 0; + boolean selectedRouteDescriptorChanged = false; + if (providerDescriptor != null && providerDescriptor.isValid()) { + final List<MediaRouteDescriptor> routeDescriptors = providerDescriptor.getRoutes(); + // Updating route group's contents requires all member routes' information. + // Add the groups to the lists and update them later. + List<Pair<RouteInfo, MediaRouteDescriptor>> addedGroups = new ArrayList<>(); + List<Pair<RouteInfo, MediaRouteDescriptor>> updatedGroups = new ArrayList<>(); + for (MediaRouteDescriptor routeDescriptor : routeDescriptors) { + final String id = routeDescriptor.getId(); + final int sourceIndex = provider.findRouteIndexByDescriptorId(id); + boolean isGroup = routeDescriptor.getGroupMemberIds() != null; + if (sourceIndex < 0) { + // 1. Add the route to the list. + String uniqueId = assignRouteUniqueId(provider, id); + RouteInfo route = isGroup ? new RouteGroup(provider, id, uniqueId) : + new RouteInfo(provider, id, uniqueId); + provider.mRoutes.add(targetIndex++, route); + mRoutes.add(route); + // 2. Create the route's contents. + if (isGroup) { + addedGroups.add(new Pair<>(route, routeDescriptor)); + } else { + route.maybeUpdateDescriptor(routeDescriptor); + // 3. Notify clients about addition. if (DEBUG) { Log.d(TAG, "Route added: " + route); } mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route); } - for (Pair<RouteInfo, MediaRouteDescriptor> pair : updatedGroups) { - RouteInfo route = pair.first; - if (updateRouteDescriptorAndNotify(route, pair.second) != 0) { + } else if (sourceIndex < targetIndex) { + Log.w(TAG, "Ignoring route descriptor with duplicate id: " + + routeDescriptor); + } else { + RouteInfo route = provider.mRoutes.get(sourceIndex); + // 1. Replace route if a group route becomes a normal route + // or vice versa. + if ((route instanceof RouteGroup) != isGroup) { + route = isGroup ? new RouteGroup(provider, id, route.getId()) : + new RouteInfo(provider, id, route.getId()); + provider.mRoutes.set(sourceIndex, route); + } + // 2. Reorder the route within the list. + Collections.swap(provider.mRoutes, sourceIndex, targetIndex++); + // 3. Update the route's contents. + if (route instanceof RouteGroup) { + updatedGroups.add(new Pair<>(route, routeDescriptor)); + } else { + // 4. Notify clients about changes. + if (updateRouteDescriptorAndNotify(route, routeDescriptor) != 0) { if (route == mSelectedRoute) { selectedRouteDescriptorChanged = true; } } } - } else { - Log.w(TAG, "Ignoring invalid provider descriptor: " + providerDescriptor); } } - - // Dispose all remaining routes that do not have matching descriptors. - for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) { - // 1. Delete the route's contents. - RouteInfo route = provider.mRoutes.get(i); - route.maybeUpdateDescriptor(null); - // 2. Remove the route from the list. - mRoutes.remove(route); - } - - // Update the selected route if needed. - updateSelectedRouteIfNeeded(selectedRouteDescriptorChanged); - - // Now notify clients about routes that were removed. - // We do this after updating the selected route to ensure - // that the framework media router observes the new route - // selection before the removal since removing the currently - // selected route may have side-effects. - for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) { - RouteInfo route = provider.mRoutes.remove(i); + // Update the new and/or existing groups. + for (Pair<RouteInfo, MediaRouteDescriptor> pair : addedGroups) { + RouteInfo route = pair.first; + route.maybeUpdateDescriptor(pair.second); if (DEBUG) { - Log.d(TAG, "Route removed: " + route); + Log.d(TAG, "Route added: " + route); + } + mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route); + } + for (Pair<RouteInfo, MediaRouteDescriptor> pair : updatedGroups) { + RouteInfo route = pair.first; + if (updateRouteDescriptorAndNotify(route, pair.second) != 0) { + if (route == mSelectedRoute) { + selectedRouteDescriptorChanged = true; + } } - mCallbackHandler.post(CallbackHandler.MSG_ROUTE_REMOVED, route); } + } else { + Log.w(TAG, "Ignoring invalid provider descriptor: " + providerDescriptor); + } + + // Dispose all remaining routes that do not have matching descriptors. + for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) { + // 1. Delete the route's contents. + RouteInfo route = provider.mRoutes.get(i); + route.maybeUpdateDescriptor(null); + // 2. Remove the route from the list. + mRoutes.remove(route); + } - // Notify provider changed. + // Update the selected route if needed. + updateSelectedRouteIfNeeded(selectedRouteDescriptorChanged); + + // Now notify clients about routes that were removed. + // We do this after updating the selected route to ensure + // that the framework media router observes the new route + // selection before the removal since removing the currently + // selected route may have side-effects. + for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) { + RouteInfo route = provider.mRoutes.remove(i); if (DEBUG) { - Log.d(TAG, "Provider changed: " + provider); + Log.d(TAG, "Route removed: " + route); } - mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_CHANGED, provider); + mCallbackHandler.post(CallbackHandler.MSG_ROUTE_REMOVED, route); + } + + // Notify provider changed. + if (DEBUG) { + Log.d(TAG, "Provider changed: " + provider); } + mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_CHANGED, provider); } private int updateRouteDescriptorAndNotify(RouteInfo route, @@ -2480,7 +2544,7 @@ public final class MediaRouter { return changes; } - private String assignRouteUniqueId(ProviderInfo provider, String routeDescriptorId) { + String assignRouteUniqueId(ProviderInfo provider, String routeDescriptorId) { // Although route descriptor ids are unique within a provider, it's // possible for there to be two providers with the same package name. // Therefore we must dedupe the composite id. @@ -2579,12 +2643,12 @@ public final class MediaRouter { } // Select route controllers for the added routes. for (RouteInfo route : routes) { - if (!mRouteControllerMap.containsKey(route.mDescriptorId)) { + if (!mRouteControllerMap.containsKey(route.mUniqueId)) { RouteController controller = route.getProviderInstance() .onCreateRouteController( route.mDescriptorId, mSelectedRoute.mDescriptorId); controller.onSelect(); - mRouteControllerMap.put(route.mDescriptorId, controller); + mRouteControllerMap.put(route.mUniqueId, controller); } } } @@ -2666,9 +2730,26 @@ public final class MediaRouter { } } - mSelectedRoute = route; - mSelectedRouteController = route.getProviderInstance().onCreateRouteController( - route.mDescriptorId); + if (route.getProvider().supportsDynamicGroup()) { + // MRP will create a new dynamic group route with initially selected route. + MediaRouteProvider.DynamicGroupRouteController controller = + route.getProviderInstance().onCreateDynamicGroupRouteController( + route.mDescriptorId); + // Controller has the new route's id which MediaRouteDescriptor might not be + // published yet. + String uniqueId = assignRouteUniqueId( + route.getProvider(), controller.getDynamicGroupRouteId()); + controller.setOnDynamicRoutesChangedListener( + MainHandlerExecutor.getExecutor(mApplicationContext), + mDynamicRoutesListener); + mSelectedRouteController = controller; + mSelectedRoute = new DynamicGroupInfo(mSelectedRoute.getProvider(), + route.mDescriptorId, uniqueId); + } else { + mSelectedRouteController = route.getProviderInstance().onCreateRouteController( + route.mDescriptorId); + mSelectedRoute = route; + } if (mSelectedRouteController != null) { mSelectedRouteController.onSelect(); } @@ -2685,7 +2766,7 @@ public final class MediaRouter { r.getProviderInstance().onCreateRouteController( r.mDescriptorId, mSelectedRoute.mDescriptorId); controller.onSelect(); - mRouteControllerMap.put(r.mDescriptorId, controller); + mRouteControllerMap.put(r.mUniqueId, controller); } } @@ -2693,16 +2774,30 @@ public final class MediaRouter { } } + DynamicGroupRouteController.OnDynamicRoutesChangedListener mDynamicRoutesListener = + new DynamicGroupRouteController.OnDynamicRoutesChangedListener() { + @Override + public void onRoutesChanged( + DynamicGroupRouteController controller, + Collection<DynamicGroupRouteController.DynamicRouteDescriptor> routes) { + if (controller == mSelectedRouteController + && controller.getDynamicGroupRouteId().equals( + mSelectedRoute.mDescriptorId) + && mSelectedRoute instanceof DynamicGroupInfo) { + ((DynamicGroupInfo) mSelectedRoute).updateDescriptors(routes); + } + } + }; + @Override public void onSystemRouteSelectedByDescriptorId(String id) { // System route is selected, do not sync the route we selected before. mCallbackHandler.removeMessages(CallbackHandler.MSG_ROUTE_SELECTED); - int providerIndex = findProviderInfo(mSystemProvider); - if (providerIndex >= 0) { - ProviderInfo provider = mProviders.get(providerIndex); - int routeIndex = provider.findRouteByDescriptorId(id); - if (routeIndex >= 0) { - provider.mRoutes.get(routeIndex).select(); + ProviderInfo provider = findProviderInfo(mSystemProvider); + if (provider != null) { + RouteInfo route = provider.findRouteByDescriptorId(id); + if (route != null) { + route.select(); } } } |