Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41cf690b authored by Bishoy Gendy's avatar Bishoy Gendy
Browse files

Add route visibility support in platform

Bug: 258800804
Test: atest CtsMediaBetterTogetherTestCases && manually through andoridx sample app.
Change-Id: I3c8ee4f35b6e140e52c300a7ea0edb660f63f8a2
parent 93bebe4f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -23716,6 +23716,8 @@ 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 @NonNull public android.media.MediaRoute2Info.Builder setVisibilityPublic();
    method @NonNull public android.media.MediaRoute2Info.Builder setVisibilityRestricted(@NonNull java.util.Set<java.lang.String>);
    method @NonNull public android.media.MediaRoute2Info.Builder setVolume(int);
    method @NonNull public android.media.MediaRoute2Info.Builder setVolumeHandling(int);
    method @NonNull public android.media.MediaRoute2Info.Builder setVolumeMax(int);
+54 −2
Original line number Diff line number Diff line
@@ -353,6 +353,8 @@ public final class MediaRoute2Info implements Parcelable {
    final Set<String> mDeduplicationIds;
    final Bundle mExtras;
    final String mProviderId;
    final boolean mIsVisibilityRestricted;
    final Set<String> mAllowedPackages;

    MediaRoute2Info(@NonNull Builder builder) {
        mId = builder.mId;
@@ -372,6 +374,8 @@ public final class MediaRoute2Info implements Parcelable {
        mDeduplicationIds = builder.mDeduplicationIds;
        mExtras = builder.mExtras;
        mProviderId = builder.mProviderId;
        mIsVisibilityRestricted = builder.mIsVisibilityRestricted;
        mAllowedPackages = builder.mAllowedPackages;
    }

    MediaRoute2Info(@NonNull Parcel in) {
@@ -393,6 +397,8 @@ public final class MediaRoute2Info implements Parcelable {
        mDeduplicationIds = Set.of(in.readStringArray());
        mExtras = in.readBundle();
        mProviderId = in.readString();
        mIsVisibilityRestricted = in.readBoolean();
        mAllowedPackages = Set.of(in.createString8Array());
    }

    /**
@@ -627,6 +633,15 @@ public final class MediaRoute2Info implements Parcelable {
        return true;
    }

    /**
     * Returns whether this route is visible to the package with the given name.
     * @hide
     */
    public boolean isVisibleTo(String packageName) {
        return !mIsVisibilityRestricted || getPackageName().equals(packageName)
                || mAllowedPackages.contains(packageName);
    }

    /**
     * Dumps the current state of the object to the given {@code pw} as a human-readable string.
     *
@@ -655,6 +670,8 @@ public final class MediaRoute2Info implements Parcelable {
        pw.println(indent + "mDeduplicationIds=" + mDeduplicationIds);
        pw.println(indent + "mExtras=" + mExtras);
        pw.println(indent + "mProviderId=" + mProviderId);
        pw.println(indent + "mIsVisibilityRestricted=" + mIsVisibilityRestricted);
        pw.println(indent + "mAllowedPackages=" + mAllowedPackages);
    }

    private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) {
@@ -705,7 +722,9 @@ public final class MediaRoute2Info implements Parcelable {
                && (mVolume == other.mVolume)
                && Objects.equals(mAddress, other.mAddress)
                && Objects.equals(mDeduplicationIds, other.mDeduplicationIds)
                && Objects.equals(mProviderId, other.mProviderId);
                && Objects.equals(mProviderId, other.mProviderId)
                && (mIsVisibilityRestricted == other.mIsVisibilityRestricted)
                && Objects.equals(mAllowedPackages, other.mAllowedPackages);
    }

    @Override
@@ -713,7 +732,8 @@ public final class MediaRoute2Info implements Parcelable {
        // Note: mExtras is not included.
        return Objects.hash(mId, mName, mFeatures, mType, mIsSystem, mIconUri, mDescription,
                mConnectionState, mClientPackageName, mPackageName, mVolumeHandling, mVolumeMax,
                mVolume, mAddress, mDeduplicationIds, mProviderId);
                mVolume, mAddress, mDeduplicationIds, mProviderId, mIsVisibilityRestricted,
                mAllowedPackages);
    }

    @Override
@@ -733,6 +753,8 @@ public final class MediaRoute2Info implements Parcelable {
                .append(", volume=").append(getVolume())
                .append(", deduplicationIds=").append(String.join(",", getDeduplicationIds()))
                .append(", providerId=").append(getProviderId())
                .append(", isVisibilityRestricted=").append(mIsVisibilityRestricted)
                .append(", allowedPackages=").append(String.join(",", mAllowedPackages))
                .append(" }");
        return result.toString();
    }
@@ -761,6 +783,8 @@ public final class MediaRoute2Info implements Parcelable {
        dest.writeStringArray(mDeduplicationIds.toArray(new String[mDeduplicationIds.size()]));
        dest.writeBundle(mExtras);
        dest.writeString(mProviderId);
        dest.writeBoolean(mIsVisibilityRestricted);
        dest.writeString8Array(mAllowedPackages.toArray(new String[0]));
    }

    /**
@@ -787,6 +811,8 @@ public final class MediaRoute2Info implements Parcelable {
        Set<String> mDeduplicationIds;
        Bundle mExtras;
        String mProviderId;
        boolean mIsVisibilityRestricted;
        Set<String> mAllowedPackages;

        /**
         * Constructor for builder to create {@link MediaRoute2Info}.
@@ -809,6 +835,7 @@ public final class MediaRoute2Info implements Parcelable {
            mName = name;
            mFeatures = new ArrayList<>();
            mDeduplicationIds = Set.of();
            mAllowedPackages = Set.of();
        }

        /**
@@ -854,6 +881,8 @@ public final class MediaRoute2Info implements Parcelable {
                mExtras = new Bundle(routeInfo.mExtras);
            }
            mProviderId = routeInfo.mProviderId;
            mIsVisibilityRestricted = routeInfo.mIsVisibilityRestricted;
            mAllowedPackages = routeInfo.mAllowedPackages;
        }

        /**
@@ -1056,6 +1085,29 @@ public final class MediaRoute2Info implements Parcelable {
            return this;
        }

        /**
         * Sets the visibility of this route to public. This is the default
         * visibility for routes that are public to all other apps.
         */
        @NonNull
        public Builder setVisibilityPublic() {
            mIsVisibilityRestricted = false;
            mAllowedPackages = Set.of();
            return this;
        }

        /**
         * Sets the visibility of this route to restricted. This means that the
         * route is only visible to a set of package name.
         * @param allowedPackages set of package names which are allowed to see this route.
         */
        @NonNull
        public Builder setVisibilityRestricted(@NonNull Set<String> allowedPackages) {
            mIsVisibilityRestricted = true;
            mAllowedPackages = Set.copyOf(allowedPackages);
            return this;
        }

        /**
         * Builds the {@link MediaRoute2Info media route info}.
         *
+9 −4
Original line number Diff line number Diff line
@@ -247,7 +247,6 @@ public final class MediaRouter2Manager {
        return getTransferableRoutes(sessions.get(sessions.size() - 1));
    }


    /**
     * Gets available routes for the given routing session.
     * The returned routes can be passed to
@@ -313,9 +312,15 @@ public final class MediaRouter2Manager {
                mDiscoveryPreferenceMap.getOrDefault(packageName, RouteDiscoveryPreference.EMPTY);

        for (MediaRoute2Info route : getSortedRoutes(discoveryPreference)) {
            if (sessionInfo.getTransferableRoutes().contains(route.getId())
                    || (includeSelectedRoutes
                    && sessionInfo.getSelectedRoutes().contains(route.getId()))) {
            if (!route.isVisibleTo(packageName)) {
                continue;
            }
            boolean transferableRoutesContainRoute =
                    sessionInfo.getTransferableRoutes().contains(route.getId());
            boolean selectedRoutesContainRoute =
                    sessionInfo.getSelectedRoutes().contains(route.getId());
            if (transferableRoutesContainRoute
                    || (includeSelectedRoutes && selectedRoutesContainRoute)) {
                routes.add(route);
                continue;
            }
+62 −20
Original line number Diff line number Diff line
@@ -1612,7 +1612,7 @@ class MediaRouter2ServiceImpl {
         * <p>This list contains all routes exposed by route providers. This includes routes from
         * both system route providers and user route providers.
         *
         * <p>See {@link #getRouters(boolean hasModifyAudioRoutingPermission)}.
         * <p>See {@link #getRouterRecords(boolean hasModifyAudioRoutingPermission)}.
         */
        private final Map<String, MediaRoute2Info> mLastNotifiedRoutesToPrivilegedRouters =
                new ArrayMap<>();
@@ -1882,9 +1882,10 @@ class MediaRouter2ServiceImpl {
            if (!hasAddedOrModifiedRoutes && !hasRemovedRoutes) {
                return;
            }

            List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true);
            List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false);
            List<RouterRecord> routerRecordsWithModifyAudioRoutingPermission =
                    getRouterRecords(true);
            List<RouterRecord> routerRecordsWithoutModifyAudioRoutingPermission =
                    getRouterRecords(false);
            List<IMediaRouter2Manager> managers = getManagers();

            // Managers receive all provider updates with all routes.
@@ -1893,22 +1894,22 @@ class MediaRouter2ServiceImpl {

            // Routers with modify audio permission (usually system routers) receive all provider
            // updates with all routes.
            notifyRoutesUpdatedToRouters(
                    routersWithModifyAudioRoutingPermission,
            notifyRoutesUpdatedToRouterRecords(
                    routerRecordsWithModifyAudioRoutingPermission,
                    new ArrayList<>(mLastNotifiedRoutesToPrivilegedRouters.values()));

            if (!isSystemProvider) {
                // Regular routers receive updates from all non-system providers with all non-system
                // routes.
                notifyRoutesUpdatedToRouters(
                        routersWithoutModifyAudioRoutingPermission,
                notifyRoutesUpdatedToRouterRecords(
                        routerRecordsWithoutModifyAudioRoutingPermission,
                        new ArrayList<>(mLastNotifiedRoutesToNonPrivilegedRouters.values()));
            } else if (hasAddedOrModifiedRoutes) {
                // On system provider updates, regular routers receive the updated default route.
                // This is the only system route they should receive.
                mLastNotifiedRoutesToNonPrivilegedRouters.put(defaultRoute.getId(), defaultRoute);
                notifyRoutesUpdatedToRouters(
                        routersWithoutModifyAudioRoutingPermission,
                notifyRoutesUpdatedToRouterRecords(
                        routerRecordsWithoutModifyAudioRoutingPermission,
                        new ArrayList<>(mLastNotifiedRoutesToNonPrivilegedRouters.values()));
            }
        }
@@ -2177,8 +2178,8 @@ class MediaRouter2ServiceImpl {
                if (mServiceRef.get() == null) {
                    return;
                }
                notifySessionInfoChangedToRouters(getRouters(true), sessionInfo);
                notifySessionInfoChangedToRouters(getRouters(false),
                notifySessionInfoChangedToRouters(getRouterRecords(true), sessionInfo);
                notifySessionInfoChangedToRouters(getRouterRecords(false),
                        mSystemProvider.getDefaultSessionInfo());
                return;
            }
@@ -2189,7 +2190,7 @@ class MediaRouter2ServiceImpl {
                        + sessionInfo);
                return;
            }
            notifySessionInfoChangedToRouters(Arrays.asList(routerRecord.mRouter), sessionInfo);
            notifySessionInfoChangedToRouters(Arrays.asList(routerRecord), sessionInfo);
        }

        private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
@@ -2302,6 +2303,7 @@ class MediaRouter2ServiceImpl {
                            == routerRecord.mHasModifyAudioRoutingPermission) {
                        routers.add(routerRecord.mRouter);
                    }
                    routers.add(routerRecord.mRouter);
                }
            }
            return routers;
@@ -2331,6 +2333,23 @@ class MediaRouter2ServiceImpl {
            }
        }

        private List<RouterRecord> getRouterRecords(boolean hasModifyAudioRoutingPermission) {
            MediaRouter2ServiceImpl service = mServiceRef.get();
            List<RouterRecord> routerRecords = new ArrayList<>();
            if (service == null) {
                return routerRecords;
            }
            synchronized (service.mLock) {
                for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
                    if (hasModifyAudioRoutingPermission
                            == routerRecord.mHasModifyAudioRoutingPermission) {
                        routerRecords.add(routerRecord);
                    }
                }
                return routerRecords;
            }
        }

        private List<ManagerRecord> getManagerRecords() {
            MediaRouter2ServiceImpl service = mServiceRef.get();
            if (service == null) {
@@ -2381,22 +2400,45 @@ class MediaRouter2ServiceImpl {
            }
        }

        private void notifyRoutesUpdatedToRouters(
                @NonNull List<IMediaRouter2> routers, @NonNull List<MediaRoute2Info> routes) {
            for (IMediaRouter2 router : routers) {
        private static void notifyRoutesUpdatedToRouterRecords(
                @NonNull List<RouterRecord> routerRecords,
                @NonNull List<MediaRoute2Info> routes) {
            for (RouterRecord routerRecord: routerRecords) {
                List<MediaRoute2Info> filteredRoutes = getFilteredRoutesForPackageName(routes,
                        routerRecord.mPackageName);
                try {
                    router.notifyRoutesUpdated(routes);
                    routerRecord.mRouter.notifyRoutesUpdated(filteredRoutes);
                } catch (RemoteException ex) {
                    Slog.w(TAG, "Failed to notify routes updated. Router probably died.", ex);
                }
            }
        }

        /**
         * Filters list of routes to return only public routes or routes provided by
         * the same package name or routes containing this package name in its allow list.
         * @param routes initial list of routes to be filtered.
         * @param packageName router's package name to filter routes for it.
         * @return only the routes that this package name is allowed to see.
         */
        private static List<MediaRoute2Info> getFilteredRoutesForPackageName(
                @NonNull List<MediaRoute2Info> routes,
                @NonNull String packageName) {
            List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
            for (MediaRoute2Info route : routes) {
                if (route.isVisibleTo(packageName)) {
                    filteredRoutes.add(route);
                }
            }
            return filteredRoutes;
        }

        private void notifySessionInfoChangedToRouters(
                @NonNull List<IMediaRouter2> routers, @NonNull RoutingSessionInfo sessionInfo) {
            for (IMediaRouter2 router : routers) {
                @NonNull List<RouterRecord> routerRecords,
                @NonNull RoutingSessionInfo sessionInfo) {
            for (RouterRecord routerRecord : routerRecords) {
                try {
                    router.notifySessionInfoChanged(sessionInfo);
                    routerRecord.mRouter.notifySessionInfoChanged(sessionInfo);
                } catch (RemoteException ex) {
                    Slog.w(TAG, "Failed to notify session info changed. Router probably died.", ex);
                }