diff --git a/core/api/current.txt b/core/api/current.txt index 80c03b4cbf891..8a54759018963 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -23351,7 +23351,6 @@ package android.media { method @NonNull public java.util.List getAllowedPackages(); method @NonNull public java.util.List getDeduplicationPackageOrder(); method @NonNull public java.util.List getPreferredFeatures(); - method @NonNull public java.util.List getRequiredFeatures(); method public boolean shouldPerformActiveScan(); method public boolean shouldRemoveDuplicates(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -23365,7 +23364,6 @@ package android.media { method @NonNull public android.media.RouteDiscoveryPreference.Builder setAllowedPackages(@NonNull java.util.List); method @NonNull public android.media.RouteDiscoveryPreference.Builder setDeduplicationPackageOrder(@NonNull java.util.List); method @NonNull public android.media.RouteDiscoveryPreference.Builder setPreferredFeatures(@NonNull java.util.List); - method @NonNull public android.media.RouteDiscoveryPreference.Builder setRequiredFeatures(@NonNull java.util.List); method @NonNull public android.media.RouteDiscoveryPreference.Builder setShouldPerformActiveScan(boolean); } diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java index afe002edfbcdf..809ee23a2b2eb 100644 --- a/media/java/android/media/MediaRoute2ProviderInfo.java +++ b/media/java/android/media/MediaRoute2ProviderInfo.java @@ -151,7 +151,7 @@ public final class MediaRoute2ProviderInfo implements Parcelable { } /** - * Sets the unique id of the provider info. + * Sets the package name and unique id of the provider info. *

* The unique id is automatically set by * {@link com.android.server.media.MediaRouterService} and used to identify providers. @@ -160,7 +160,7 @@ public final class MediaRoute2ProviderInfo implements Parcelable { * @hide */ @NonNull - public Builder setUniqueId(@Nullable String uniqueId) { + public Builder setUniqueId(@Nullable String packageName, @Nullable String uniqueId) { if (TextUtils.equals(mUniqueId, uniqueId)) { return this; } @@ -169,6 +169,7 @@ public final class MediaRoute2ProviderInfo implements Parcelable { final ArrayMap newRoutes = new ArrayMap<>(); for (Map.Entry entry : mRoutes.entrySet()) { MediaRoute2Info routeWithProviderId = new MediaRoute2Info.Builder(entry.getValue()) + .setPackageName(packageName) .setProviderId(mUniqueId) .build(); newRoutes.put(routeWithProviderId.getOriginalId(), routeWithProviderId); diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index b485eb51380d3..f8c47e83595b5 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -478,13 +478,8 @@ public final class MediaRouter2 { if (mShouldUpdateRoutes) { mShouldUpdateRoutes = false; - List filteredRoutes = new ArrayList<>(); - for (MediaRoute2Info route : mRoutes.values()) { - if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { - filteredRoutes.add(route); - } - } - mFilteredRoutes = Collections.unmodifiableList(filteredRoutes); + mFilteredRoutes = Collections.unmodifiableList( + filterRoutes(List.copyOf(mRoutes.values()), mDiscoveryPreference)); } } return mFilteredRoutes; @@ -1087,16 +1082,17 @@ public final class MediaRouter2 { List filteredRoutes = new ArrayList<>(); for (MediaRoute2Info route : getSortedRoutes(routes, discoveryPreference)) { - if (!route.hasAllFeatures(discoveryPreference.getRequiredFeatures()) - || !route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) { + if (!route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) { continue; } if (!discoveryPreference.getAllowedPackages().isEmpty() - && !discoveryPreference.getAllowedPackages().contains(route.getPackageName())) { + && (route.getPackageName() == null + || !discoveryPreference.getAllowedPackages() + .contains(route.getPackageName()))) { continue; } if (discoveryPreference.shouldRemoveDuplicates()) { - if (Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) { + if (!Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) { continue; } deduplicationIdSet.addAll(route.getDeduplicationIds()); @@ -2087,19 +2083,17 @@ public final class MediaRouter2 { } @Override - public void onPreferredFeaturesChanged(@NonNull String packageName, - @NonNull List preferredFeatures) { + public void onDiscoveryPreferenceChanged(@NonNull String packageName, + @NonNull RouteDiscoveryPreference preference) { if (!TextUtils.equals(mClientPackageName, packageName)) { return; } synchronized (mLock) { - mDiscoveryPreference = new RouteDiscoveryPreference.Builder( - preferredFeatures, true).build(); + mDiscoveryPreference = preference; } - updateAllRoutesFromManager(); - notifyPreferredFeaturesChanged(preferredFeatures); + notifyPreferredFeaturesChanged(preference.getPreferredFeatures()); } @Override diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 8635c0ea762cf..071667a0e932f 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -254,7 +254,7 @@ public final class MediaRouter2Manager { @NonNull public List getAvailableRoutes(@NonNull RoutingSessionInfo sessionInfo) { return getFilteredRoutes(sessionInfo, /*includeSelectedRoutes=*/true, - null); + /*additionalFilter=*/null); } /** @@ -315,20 +315,20 @@ public final class MediaRouter2Manager { routes.add(route); continue; } - if (!route.hasAllFeatures(discoveryPreference.getRequiredFeatures()) - || !route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) { + if (!route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) { continue; } if (!discoveryPreference.getAllowedPackages().isEmpty() - && !discoveryPreference.getAllowedPackages() - .contains(route.getPackageName())) { + && (route.getPackageName() == null + || !discoveryPreference.getAllowedPackages() + .contains(route.getPackageName()))) { continue; } if (additionalFilter != null && !additionalFilter.test(route)) { continue; } if (discoveryPreference.shouldRemoveDuplicates()) { - if (Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) { + if (!Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) { continue; } deduplicationIdSet.addAll(route.getDeduplicationIds()); diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java index e609226c3cb8d..0ba36feb4ce9c 100644 --- a/media/java/android/media/RouteDiscoveryPreference.java +++ b/media/java/android/media/RouteDiscoveryPreference.java @@ -24,7 +24,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -65,8 +64,6 @@ public final class RouteDiscoveryPreference implements Parcelable { @NonNull private final List mPreferredFeatures; @NonNull - private final List mRequiredFeatures; - @NonNull private final List mPackageOrder; @NonNull private final List mAllowedPackages; @@ -85,7 +82,6 @@ public final class RouteDiscoveryPreference implements Parcelable { RouteDiscoveryPreference(@NonNull Builder builder) { mPreferredFeatures = builder.mPreferredFeatures; - mRequiredFeatures = builder.mRequiredFeatures; mPackageOrder = builder.mPackageOrder; mAllowedPackages = builder.mAllowedPackages; mShouldPerformActiveScan = builder.mActiveScan; @@ -94,7 +90,6 @@ public final class RouteDiscoveryPreference implements Parcelable { RouteDiscoveryPreference(@NonNull Parcel in) { mPreferredFeatures = in.createStringArrayList(); - mRequiredFeatures = in.createStringArrayList(); mPackageOrder = in.createStringArrayList(); mAllowedPackages = in.createStringArrayList(); mShouldPerformActiveScan = in.readBoolean(); @@ -109,29 +104,12 @@ public final class RouteDiscoveryPreference implements Parcelable { * {@link MediaRoute2Info#FEATURE_LIVE_AUDIO}, {@link MediaRoute2Info#FEATURE_LIVE_VIDEO}, * or {@link MediaRoute2Info#FEATURE_REMOTE_PLAYBACK} or custom features defined by a provider. *

- * - * @see #getRequiredFeatures() */ @NonNull public List getPreferredFeatures() { return mPreferredFeatures; } - /** - * Gets the required features of routes that media router would like to discover. - *

- * Routes that have all the required features will be discovered. - * They may include predefined features such as - * {@link MediaRoute2Info#FEATURE_LIVE_AUDIO}, {@link MediaRoute2Info#FEATURE_LIVE_VIDEO}, - * or {@link MediaRoute2Info#FEATURE_REMOTE_PLAYBACK} or custom features defined by a provider. - * - * @see #getPreferredFeatures() - */ - @NonNull - public List getRequiredFeatures() { - return mRequiredFeatures; - } - /** * Gets the ordered list of package names used to remove duplicate routes. *

@@ -193,7 +171,6 @@ public final class RouteDiscoveryPreference implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeStringList(mPreferredFeatures); - dest.writeStringList(mRequiredFeatures); dest.writeStringList(mPackageOrder); dest.writeStringList(mAllowedPackages); dest.writeBoolean(mShouldPerformActiveScan); @@ -224,7 +201,6 @@ public final class RouteDiscoveryPreference implements Parcelable { } RouteDiscoveryPreference other = (RouteDiscoveryPreference) o; return Objects.equals(mPreferredFeatures, other.mPreferredFeatures) - && Objects.equals(mRequiredFeatures, other.mRequiredFeatures) && Objects.equals(mPackageOrder, other.mPackageOrder) && Objects.equals(mAllowedPackages, other.mAllowedPackages) && mShouldPerformActiveScan == other.mShouldPerformActiveScan; @@ -232,7 +208,7 @@ public final class RouteDiscoveryPreference implements Parcelable { @Override public int hashCode() { - return Objects.hash(mPreferredFeatures, mRequiredFeatures, mPackageOrder, mAllowedPackages, + return Objects.hash(mPreferredFeatures, mPackageOrder, mAllowedPackages, mShouldPerformActiveScan); } @@ -241,7 +217,6 @@ public final class RouteDiscoveryPreference implements Parcelable { */ public static final class Builder { List mPreferredFeatures; - List mRequiredFeatures; List mPackageOrder; List mAllowedPackages; @@ -253,7 +228,6 @@ public final class RouteDiscoveryPreference implements Parcelable { Objects.requireNonNull(preferredFeatures, "preferredFeatures must not be null"); mPreferredFeatures = preferredFeatures.stream().filter(str -> !TextUtils.isEmpty(str)) .collect(Collectors.toList()); - mRequiredFeatures = List.of(); mPackageOrder = List.of(); mAllowedPackages = List.of(); mActiveScan = activeScan; @@ -263,7 +237,6 @@ public final class RouteDiscoveryPreference implements Parcelable { Objects.requireNonNull(preference, "preference must not be null"); mPreferredFeatures = preference.getPreferredFeatures(); - mRequiredFeatures = preference.getRequiredFeatures(); mPackageOrder = preference.getDeduplicationPackageOrder(); mAllowedPackages = preference.getAllowedPackages(); mActiveScan = preference.shouldPerformActiveScan(); @@ -271,14 +244,8 @@ public final class RouteDiscoveryPreference implements Parcelable { } /** - * A constructor to combine multiple preferences into a single preference. The combined - * preference will discover a superset of the union of the routes discoverable by each of - * the individual preferences. - *

- * When routes need to be discovered for multiple preferences, the combined preference can - * be used to query route providers once and obtain all routes of interest. The obtained - * routes can then be filtered for each of the individual preferences. This is typically - * more efficient than querying route providers with each of the individual preferences. + * A constructor to combine multiple preferences into a single preference. + * It ignores extras of preferences. * * @hide */ @@ -286,15 +253,21 @@ public final class RouteDiscoveryPreference implements Parcelable { Objects.requireNonNull(preferences, "preferences must not be null"); Set preferredFeatures = new HashSet<>(); + Set allowedPackages = new HashSet<>(); + mPackageOrder = List.of(); boolean activeScan = false; for (RouteDiscoveryPreference preference : preferences) { preferredFeatures.addAll(preference.mPreferredFeatures); + + allowedPackages.addAll(preference.mAllowedPackages); activeScan |= preference.mShouldPerformActiveScan; + // Choose one of either + if (mPackageOrder.isEmpty() && !preference.mPackageOrder.isEmpty()) { + mPackageOrder = List.copyOf(preference.mPackageOrder); + } } - mPreferredFeatures = new ArrayList<>(preferredFeatures); - mRequiredFeatures = List.of(); - mPackageOrder = List.of(); - mAllowedPackages = List.of(); + mPreferredFeatures = List.copyOf(preferredFeatures); + mAllowedPackages = List.copyOf(allowedPackages); mActiveScan = activeScan; } @@ -315,17 +288,6 @@ public final class RouteDiscoveryPreference implements Parcelable { return this; } - /** - * Sets the required route features to discover. - */ - @NonNull - public Builder setRequiredFeatures(@NonNull List requiredFeatures) { - Objects.requireNonNull(requiredFeatures, "preferredFeatures must not be null"); - mRequiredFeatures = requiredFeatures.stream().filter(str -> !TextUtils.isEmpty(str)) - .collect(Collectors.toList()); - return this; - } - /** * Sets the list of package names of providers that media router would like to discover. *

diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java index d7e9ae99a0bf9..b4aad9df64a7d 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java @@ -71,6 +71,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -276,6 +277,42 @@ public class MediaRouter2ManagerTest { assertNotNull(routes.get(ROUTE_ID_SPECIAL_FEATURE)); } + @Test + public void testNoAllowedPackages_returnsZeroRoutes() throws Exception { + RouteDiscoveryPreference preference = + new RouteDiscoveryPreference.Builder(FEATURES_ALL, true) + .setAllowedPackages(List.of("random package name")) + .build(); + Map routes = waitAndGetRoutesWithManager(preference); + + int remoteRouteCount = 0; + for (MediaRoute2Info route : routes.values()) { + if (!route.isSystemRoute()) { + remoteRouteCount++; + } + } + + assertEquals(0, remoteRouteCount); + } + + @Test + public void testAllowedPackages() throws Exception { + RouteDiscoveryPreference preference = + new RouteDiscoveryPreference.Builder(FEATURES_ALL, true) + .setAllowedPackages(List.of("com.android.mediaroutertest")) + .build(); + Map routes = waitAndGetRoutesWithManager(preference); + + int remoteRouteCount = 0; + for (MediaRoute2Info route : routes.values()) { + if (!route.isSystemRoute()) { + remoteRouteCount++; + } + } + + assertTrue(remoteRouteCount > 0); + } + /** * Tests if MR2.SessionCallback.onSessionCreated is called * when a route is selected from MR2Manager. @@ -818,8 +855,14 @@ public class MediaRouter2ManagerTest { Map waitAndGetRoutesWithManager(List routeFeatures) throws Exception { + return waitAndGetRoutesWithManager( + new RouteDiscoveryPreference.Builder(routeFeatures, true).build()); + } + + Map waitAndGetRoutesWithManager(RouteDiscoveryPreference preference) + throws Exception { CountDownLatch addedLatch = new CountDownLatch(1); - CountDownLatch featuresLatch = new CountDownLatch(1); + CountDownLatch preferenceLatch = new CountDownLatch(1); // A dummy callback is required to send route feature info. RouteCallback routeCallback = new RouteCallback() {}; @@ -828,7 +871,8 @@ public class MediaRouter2ManagerTest { public void onRoutesAdded(List routes) { for (MediaRoute2Info route : routes) { if (!route.isSystemRoute() - && hasMatchingFeature(route.getFeatures(), routeFeatures)) { + && hasMatchingFeature(route.getFeatures(), preference + .getPreferredFeatures())) { addedLatch.countDown(); break; } @@ -836,20 +880,19 @@ public class MediaRouter2ManagerTest { } @Override - public void onPreferredFeaturesChanged(String packageName, - List preferredFeatures) { + public void onDiscoveryPreferenceChanged(String packageName, + RouteDiscoveryPreference discoveryPreference) { if (TextUtils.equals(mPackageName, packageName) - && preferredFeatures.size() == routeFeatures.size() - && preferredFeatures.containsAll(routeFeatures)) { - featuresLatch.countDown(); + && Objects.equals(preference, discoveryPreference)) { + preferenceLatch.countDown(); } } }; mManager.registerCallback(mExecutor, managerCallback); - mRouter2.registerRouteCallback(mExecutor, routeCallback, - new RouteDiscoveryPreference.Builder(routeFeatures, true).build()); + mRouter2.registerRouteCallback(mExecutor, routeCallback, preference); + try { - featuresLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS); + preferenceLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS); if (mManager.getAvailableRoutes(mPackageName).isEmpty()) { addedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS); } diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index 204ebfc678f5d..b82e3a31567e3 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -86,7 +86,7 @@ abstract class MediaRoute2Provider { mProviderInfo = null; } else { mProviderInfo = new MediaRoute2ProviderInfo.Builder(providerInfo) - .setUniqueId(mUniqueId) + .setUniqueId(mComponentName.getPackageName(), mUniqueId) .setSystemRouteProvider(mIsSystemRouteProvider) .build(); } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 7f997df3b222b..b3072667130b4 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -64,9 +64,11 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -2200,9 +2202,21 @@ class MediaRouter2ServiceImpl { } } + // Build a composite RouteDiscoveryPreference that matches all of the routes + // that match one or more of the individual discovery preferences. It may also + // match additional routes. The composite RouteDiscoveryPreference can be used + // to query route providers once to obtain all of the routes of interest, which + // can be subsequently filtered for the individual discovery preferences. + Set preferredFeatures = new HashSet<>(); + boolean activeScan = false; + for (RouteDiscoveryPreference preference : discoveryPreferences) { + preferredFeatures.addAll(preference.getPreferredFeatures()); + activeScan |= preference.shouldPerformActiveScan(); + } + RouteDiscoveryPreference newPreference = new RouteDiscoveryPreference.Builder( + List.copyOf(preferredFeatures), activeScan).build(); + synchronized (service.mLock) { - RouteDiscoveryPreference newPreference = - new RouteDiscoveryPreference.Builder(discoveryPreferences).build(); if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) { return; }