diff options
| -rw-r--r-- | core/api/current.txt | 2 | ||||
| -rw-r--r-- | media/java/android/media/MediaRoute2Info.java | 36 | ||||
| -rw-r--r-- | services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java | 26 |
3 files changed, 61 insertions, 3 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 1d11cac13197..6fb319b68f28 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -24861,6 +24861,7 @@ package android.media { method @Nullable public android.net.Uri getIconUri(); method @NonNull public String getId(); method @NonNull public CharSequence getName(); + method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public java.util.Set<java.lang.String> getRequiredPermissions(); method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public int getSuitabilityStatus(); method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public int getSupportedRoutingTypes(); method public int getType(); @@ -24929,6 +24930,7 @@ package android.media { method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence); method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle); method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri); + method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public android.media.MediaRoute2Info.Builder setRequiredPermissions(@NonNull java.util.Set<java.lang.String>); method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") @NonNull public android.media.MediaRoute2Info.Builder setSuitabilityStatus(int); method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @NonNull public android.media.MediaRoute2Info.Builder setSupportedRoutingTypes(int); method @NonNull public android.media.MediaRoute2Info.Builder setType(int); diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index d433ec876af9..dd5067a3ee67 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -24,6 +24,7 @@ import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_S import static com.android.media.flags.Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2; import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES; import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES; +import static com.android.media.flags.Flags.FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -616,6 +617,7 @@ public final class MediaRoute2Info implements Parcelable { private final String mProviderId; private final boolean mIsVisibilityRestricted; private final Set<String> mAllowedPackages; + private final Set<String> mRequiredPermissions; @SuitabilityStatus private final int mSuitabilityStatus; MediaRoute2Info(@NonNull Builder builder) { @@ -640,6 +642,7 @@ public final class MediaRoute2Info implements Parcelable { mIsVisibilityRestricted = builder.mIsVisibilityRestricted; mAllowedPackages = builder.mAllowedPackages; mSuitabilityStatus = builder.mSuitabilityStatus; + mRequiredPermissions = Set.copyOf(builder.mRequiredPermissions); } MediaRoute2Info(@NonNull Parcel in) { @@ -664,6 +667,7 @@ public final class MediaRoute2Info implements Parcelable { mProviderId = in.readString(); mIsVisibilityRestricted = in.readBoolean(); mAllowedPackages = Set.of(in.createString8Array()); + mRequiredPermissions = Set.of(in.createString8Array()); mSuitabilityStatus = in.readInt(); } @@ -907,6 +911,15 @@ public final class MediaRoute2Info implements Parcelable { } /** + * @return the set of permissions which must be held to see this route + */ + @NonNull + @FlaggedApi(FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API) + public Set<String> getRequiredPermissions() { + return mRequiredPermissions; + } + + /** * Returns whether this route's type can only be published by the system route provider. * * @see #isSystemRoute() @@ -977,6 +990,7 @@ public final class MediaRoute2Info implements Parcelable { pw.println(indent + "mIsVisibilityRestricted=" + mIsVisibilityRestricted); pw.println(indent + "mAllowedPackages=" + mAllowedPackages); pw.println(indent + "mSuitabilityStatus=" + mSuitabilityStatus); + pw.println(indent + "mRequiredPermissions=" + mRequiredPermissions); } private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) { @@ -1013,6 +1027,7 @@ public final class MediaRoute2Info implements Parcelable { && Objects.equals(mProviderId, other.mProviderId) && (mIsVisibilityRestricted == other.mIsVisibilityRestricted) && Objects.equals(mAllowedPackages, other.mAllowedPackages) + && Objects.equals(mRequiredPermissions, other.mRequiredPermissions) && mSuitabilityStatus == other.mSuitabilityStatus; } @@ -1039,6 +1054,7 @@ public final class MediaRoute2Info implements Parcelable { mProviderId, mIsVisibilityRestricted, mAllowedPackages, + mRequiredPermissions, mSuitabilityStatus); } @@ -1079,6 +1095,8 @@ public final class MediaRoute2Info implements Parcelable { .append(mIsVisibilityRestricted) .append(", allowedPackages=") .append(String.join(",", mAllowedPackages)) + .append(", mRequiredPermissions=") + .append(String.join(",", mRequiredPermissions)) .append(", suitabilityStatus=") .append(mSuitabilityStatus) .append(" }") @@ -1112,6 +1130,7 @@ public final class MediaRoute2Info implements Parcelable { dest.writeString(mProviderId); dest.writeBoolean(mIsVisibilityRestricted); dest.writeString8Array(mAllowedPackages.toArray(new String[0])); + dest.writeString8Array(mRequiredPermissions.toArray(new String[0])); dest.writeInt(mSuitabilityStatus); } @@ -1260,6 +1279,7 @@ public final class MediaRoute2Info implements Parcelable { private String mProviderId; private boolean mIsVisibilityRestricted; private Set<String> mAllowedPackages; + private Set<String> mRequiredPermissions; @SuitabilityStatus private int mSuitabilityStatus; /** @@ -1285,6 +1305,7 @@ public final class MediaRoute2Info implements Parcelable { mDeduplicationIds = Set.of(); mAllowedPackages = Set.of(); mSuitabilityStatus = SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER; + mRequiredPermissions = Set.of(); } /** @@ -1334,6 +1355,7 @@ public final class MediaRoute2Info implements Parcelable { mIsVisibilityRestricted = routeInfo.mIsVisibilityRestricted; mAllowedPackages = routeInfo.mAllowedPackages; mSuitabilityStatus = routeInfo.mSuitabilityStatus; + mRequiredPermissions = routeInfo.mRequiredPermissions; } /** @@ -1565,6 +1587,7 @@ public final class MediaRoute2Info implements Parcelable { public Builder setVisibilityPublic() { mIsVisibilityRestricted = false; mAllowedPackages = Set.of(); + mRequiredPermissions = Set.of(); return this; } @@ -1589,6 +1612,19 @@ public final class MediaRoute2Info implements Parcelable { } /** + * Limits the visibility of this route to holders of a set of permissions. + * + * @param requiredPermissions the list of all permissions which must be held in order to + * see this route. + */ + @NonNull + @FlaggedApi(FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API) + public Builder setRequiredPermissions(@NonNull Set<String> requiredPermissions) { + mRequiredPermissions = Set.copyOf(requiredPermissions); + return this; + } + + /** * Sets route suitability status. * * <p>The default value is {@link diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 2d2d2584edfd..1abe5261e3e3 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -1144,6 +1144,7 @@ class MediaRouter2ServiceImpl { UserRecord userRecord = getOrCreateUserRecordLocked(userId); RouterRecord routerRecord = new RouterRecord( + mContext, userRecord, router, uid, @@ -2063,6 +2064,7 @@ class MediaRouter2ServiceImpl { } final class RouterRecord implements IBinder.DeathRecipient { + public final Context mContext; public final UserRecord mUserRecord; public final String mPackageName; public final List<Integer> mSelectRouteSequenceNumbers; @@ -2081,6 +2083,7 @@ class MediaRouter2ServiceImpl { @Nullable public RouteListingPreference mRouteListingPreference; RouterRecord( + Context context, UserRecord userRecord, IMediaRouter2 router, int uid, @@ -2090,6 +2093,7 @@ class MediaRouter2ServiceImpl { boolean hasModifyAudioRoutingPermission, boolean hasMediaContentControlPermission, boolean hasMediaRoutingControl) { + mContext = context; mUserRecord = userRecord; mPackageName = packageName; mSelectRouteSequenceNumbers = new ArrayList<>(); @@ -2331,18 +2335,34 @@ class MediaRouter2ServiceImpl { } /** - * Returns a filtered copy of {@code routes} that contains only the routes that are {@link - * MediaRoute2Info#isVisibleTo visible} to the router corresponding to this record. + * Returns a filtered copy of {@code routes} that contains only the routes that are visible + * to this RouterRecord. */ private List<MediaRoute2Info> getVisibleRoutes(@NonNull List<MediaRoute2Info> routes) { List<MediaRoute2Info> filteredRoutes = new ArrayList<>(); for (MediaRoute2Info route : routes) { - if (route.isVisibleTo(mPackageName)) { + if (route.isVisibleTo(mPackageName) && hasPermissionsToSeeRoute(route)) { filteredRoutes.add(route); } } return filteredRoutes; } + + /** + * @return whether this RouterRecord has the required permissions to see the given route. + */ + private boolean hasPermissionsToSeeRoute(MediaRoute2Info route) { + if (!Flags.enableRouteVisibilityControlApi()) { + return true; + } + for (String permission : route.getRequiredPermissions()) { + if (mContext.checkPermission(permission, mPid, mUid) + != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } } final class ManagerRecord implements IBinder.DeathRecipient { |