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

Commit ae8da20d authored by Derek Jedral's avatar Derek Jedral Committed by Android (Google) Code Review
Browse files

Merge "Add device suggestions API" into main

parents d5596f5e f50e3446
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.media;

import android.media.MediaRoute2Info;
import android.media.RoutingSessionInfo;
import android.media.SuggestedDeviceInfo;
import android.os.Bundle;
import android.os.UserHandle;

@@ -37,4 +38,6 @@ oneway interface IMediaRouter2 {
     */
    void requestCreateSessionByManager(long uniqueRequestId, in RoutingSessionInfo oldSession,
        in MediaRoute2Info route);
    void notifyDeviceSuggestionsUpdated(String suggestingPackageName,
        in List<SuggestedDeviceInfo> suggestions);
}
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.media.MediaRoute2Info;
import android.media.RouteDiscoveryPreference;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
import android.media.SuggestedDeviceInfo;

/**
 * {@hide}
@@ -33,6 +34,8 @@ oneway interface IMediaRouter2Manager {
            in RouteDiscoveryPreference discoveryPreference);
    void notifyRouteListingPreferenceChange(String packageName,
            in @nullable RouteListingPreference routeListingPreference);
    void notifyDeviceSuggestionsUpdated(String packageName, String suggestingPackageName,
            in @nullable List<SuggestedDeviceInfo> suggestedDeviceInfo);
    void notifyRoutesUpdated(in List<MediaRoute2Info> routes);
    void notifyRequestFailed(int requestId, int reason);
    void invalidateInstance();
+9 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.media.MediaRouterClientState;
import android.media.RouteDiscoveryPreference;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
import android.media.SuggestedDeviceInfo;
import android.os.Bundle;
import android.os.UserHandle;
/**
@@ -72,6 +73,10 @@ interface IMediaRouterService {
            in MediaRoute2Info route);
    void setSessionVolumeWithRouter2(IMediaRouter2 router, String sessionId, int volume);
    void releaseSessionWithRouter2(IMediaRouter2 router, String sessionId);
    void setDeviceSuggestionsWithRouter2(IMediaRouter2 router,
            in @nullable List<SuggestedDeviceInfo> suggestedDeviceInfo);
    @nullable Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestionsWithRouter2(
            IMediaRouter2 router);

    // Methods for MediaRouter2Manager
    List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager);
@@ -98,4 +103,8 @@ interface IMediaRouterService {
            String sessionId, int volume);
    void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId, String sessionId);
    boolean showMediaOutputSwitcherWithProxyRouter(IMediaRouter2Manager manager);
    void setDeviceSuggestionsWithManager(IMediaRouter2Manager manager,
            in @nullable List<SuggestedDeviceInfo> suggestedDeviceInfo);
    @nullable Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestionsWithManager(
            IMediaRouter2Manager manager);
}
+226 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static com.android.media.flags.Flags.FLAG_ENABLE_GET_TRANSFERABLE_ROUTES;
import static com.android.media.flags.Flags.FLAG_ENABLE_PRIVILEGED_ROUTING_FOR_MEDIA_ROUTING_CONTROL;
import static com.android.media.flags.Flags.FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2;
import static com.android.media.flags.Flags.FLAG_ENABLE_SCREEN_OFF_SCANNING;
import static com.android.media.flags.Flags.FLAG_ENABLE_SUGGESTED_DEVICE_API;

import android.Manifest;
import android.annotation.CallbackExecutor;
@@ -159,6 +160,8 @@ public final class MediaRouter2 {
            new CopyOnWriteArrayList<>();
    private final CopyOnWriteArrayList<ControllerCallbackRecord> mControllerCallbackRecords =
            new CopyOnWriteArrayList<>();
    private final CopyOnWriteArrayList<DeviceSuggestionsCallbackRecord>
            mDeviceSuggestionsCallbackRecords = new CopyOnWriteArrayList<>();

    private final CopyOnWriteArrayList<ControllerCreationRequest> mControllerCreationRequests =
            new CopyOnWriteArrayList<>();
@@ -198,6 +201,10 @@ public final class MediaRouter2 {
    @Nullable
    private RouteListingPreference mRouteListingPreference;

    @GuardedBy("mLock")
    @Nullable
    private Map<String, List<SuggestedDeviceInfo>> mSuggestedDeviceInfo = new HashMap<>();

    /**
     * Stores an auxiliary copy of {@link #mFilteredRoutes} at the time of the last route callback
     * dispatch. This is only used to determine what callback a route should be assigned to (added,
@@ -759,6 +766,27 @@ public final class MediaRouter2 {
        mListingPreferenceCallbackRecords.add(record);
    }

    /**
     * Registers the given callback to be invoked when the {@link SuggestedDeviceInfo} of the target
     * router changes.
     *
     * <p>Calls using a previously registered callback will overwrite the previous executor.
     *
     * @hide
     */
    public void registerDeviceSuggestionsCallback(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull DeviceSuggestionsCallback deviceSuggestionsCallback) {
        Objects.requireNonNull(executor, "executor must not be null");
        Objects.requireNonNull(deviceSuggestionsCallback, "callback must not be null");

        DeviceSuggestionsCallbackRecord record =
                new DeviceSuggestionsCallbackRecord(executor, deviceSuggestionsCallback);

        mDeviceSuggestionsCallbackRecords.remove(record);
        mDeviceSuggestionsCallbackRecords.add(record);
    }

    /**
     * Unregisters the given callback to not receive {@link RouteListingPreference} change events.
     *
@@ -778,6 +806,21 @@ public final class MediaRouter2 {
        }
    }

    /**
     * Unregisters the given callback to not receive {@link SuggestedDeviceInfo} change events.
     *
     * @see #registerDeviceSuggestionsCallback(Executor, DeviceSuggestionsCallback)
     * @hide
     */
    public void unregisterDeviceSuggestionsCallback(@NonNull DeviceSuggestionsCallback callback) {
        Objects.requireNonNull(callback, "callback must not be null");

        if (!mDeviceSuggestionsCallbackRecords.remove(
                new DeviceSuggestionsCallbackRecord(/* executor */ null, callback))) {
            Log.w(TAG, "unregisterDeviceSuggestionsCallback: Ignoring an unknown" + " callback");
        }
    }

    /**
     * Shows the system output switcher dialog.
     *
@@ -831,6 +874,36 @@ public final class MediaRouter2 {
        mImpl.setRouteListingPreference(routeListingPreference);
    }

    /**
     * Sets the suggested devices.
     *
     * <p>Use this method to inform the system UI that this device is suggested in the Output
     * Switcher and media controls.
     *
     * <p>You should pass null to this method to clear a previously set suggestion without setting a
     * new one.
     *
     * @param suggestedDeviceInfo The {@link SuggestedDeviceInfo} the router suggests should be
     *     provided to the user.
     * @hide
     */
    @FlaggedApi(FLAG_ENABLE_SUGGESTED_DEVICE_API)
    public void setDeviceSuggestions(@Nullable List<SuggestedDeviceInfo> suggestedDeviceInfo) {
        mImpl.setDeviceSuggestions(suggestedDeviceInfo);
    }

    /**
     * Gets the current suggested devices.
     *
     * @return the suggested devices, keyed by the package name providing each suggestion list.
     * @hide
     */
    @FlaggedApi(FLAG_ENABLE_SUGGESTED_DEVICE_API)
    @Nullable
    public Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestions() {
        return mImpl.getDeviceSuggestions();
    }

    /**
     * Returns the current {@link RouteListingPreference} of the target router.
     *
@@ -1518,6 +1591,17 @@ public final class MediaRouter2 {
        }
    }

    private void notifyDeviceSuggestionsUpdated(
            @NonNull String suggestingPackageName,
            @Nullable List<SuggestedDeviceInfo> deviceSuggestions) {
        for (DeviceSuggestionsCallbackRecord record : mDeviceSuggestionsCallbackRecords) {
            record.mExecutor.execute(
                    () ->
                            record.mDeviceSuggestionsCallback.onSuggestionUpdated(
                                    suggestingPackageName, deviceSuggestions));
        }
    }

    private void notifyTransfer(RoutingController oldController, RoutingController newController) {
        for (TransferCallbackRecord record : mTransferCallbackRecords) {
            record.mExecutor.execute(
@@ -1568,6 +1652,25 @@ public final class MediaRouter2 {
                .build();
    }

    /**
     * Callback for receiving events about device suggestions
     *
     * @hide
     */
    public interface DeviceSuggestionsCallback {

        /**
         * Called when suggestions are updated. Whenever you register a callback, this will be
         * invoked with the current suggestions.
         *
         * @param suggestingPackageName the package that provided the suggestions.
         * @param suggestedDeviceInfo the suggestions provided by the package.
         */
        void onSuggestionUpdated(
                @NonNull String suggestingPackageName,
                @Nullable List<SuggestedDeviceInfo> suggestedDeviceInfo);
    }

    /** Callback for receiving events about media route discovery. */
    public abstract static class RouteCallback {
        /**
@@ -2326,6 +2429,35 @@ public final class MediaRouter2 {
        }
    }

    private static final class DeviceSuggestionsCallbackRecord {
        public final Executor mExecutor;
        public final DeviceSuggestionsCallback mDeviceSuggestionsCallback;

        /* package */ DeviceSuggestionsCallbackRecord(
                @NonNull Executor executor,
                @NonNull DeviceSuggestionsCallback deviceSuggestionsCallback) {
            mExecutor = executor;
            mDeviceSuggestionsCallback = deviceSuggestionsCallback;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof DeviceSuggestionsCallbackRecord)) {
                return false;
            }
            return mDeviceSuggestionsCallback
                    == ((DeviceSuggestionsCallbackRecord) obj).mDeviceSuggestionsCallback;
        }

        @Override
        public int hashCode() {
            return mDeviceSuggestionsCallback.hashCode();
        }
    }

    static final class TransferCallbackRecord {
        public final Executor mExecutor;
        public final TransferCallback mTransferCallback;
@@ -2445,6 +2577,17 @@ public final class MediaRouter2 {
                            sessionInfo));
        }

        @Override
        public void notifyDeviceSuggestionsUpdated(
                String suggestingPackageName, List<SuggestedDeviceInfo> suggestions) {
            mHandler.sendMessage(
                    obtainMessage(
                            MediaRouter2::notifyDeviceSuggestionsUpdated,
                            MediaRouter2.this,
                            suggestingPackageName,
                            suggestions));
        }

        @Override
        public void requestCreateSessionByManager(
                long managerRequestId, RoutingSessionInfo oldSession, MediaRoute2Info route) {
@@ -2487,6 +2630,11 @@ public final class MediaRouter2 {

        void setRouteListingPreference(@Nullable RouteListingPreference preference);

        void setDeviceSuggestions(@Nullable List<SuggestedDeviceInfo> suggestedDeviceInfo);

        @Nullable
        Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestions();

        boolean showSystemOutputSwitcher();

        List<MediaRoute2Info> getAllRoutes();
@@ -2686,6 +2834,29 @@ public final class MediaRouter2 {
                    "RouteListingPreference cannot be set by a proxy MediaRouter2 instance.");
        }

        @Override
        public void setDeviceSuggestions(@Nullable List<SuggestedDeviceInfo> suggestedDeviceInfo) {
            synchronized (mLock) {
                try {
                    mMediaRouterService.setDeviceSuggestionsWithManager(
                            mClient, suggestedDeviceInfo);
                } catch (RemoteException ex) {
                    ex.rethrowFromSystemServer();
                }
            }
        }

        @Override
        public Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestions() {
            synchronized (mLock) {
                try {
                    return mMediaRouterService.getDeviceSuggestionsWithManager(mClient);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
        }

        @Override
        public boolean showSystemOutputSwitcher() {
            try {
@@ -3296,6 +3467,23 @@ public final class MediaRouter2 {
            notifyRouteListingPreferenceUpdated(routeListingPreference);
        }

        private void onDeviceSuggestionsChangeHandler(
                @NonNull String packageName,
                @NonNull String suggestingPackageName,
                @Nullable List<SuggestedDeviceInfo> suggestedDeviceInfo) {
            if (!TextUtils.equals(getClientPackageName(), packageName)) {
                return;
            }
            synchronized (mLock) {
                if (Objects.equals(
                        mSuggestedDeviceInfo.get(suggestingPackageName), suggestedDeviceInfo)) {
                    return;
                }
                mSuggestedDeviceInfo.put(suggestingPackageName, suggestedDeviceInfo);
            }
            notifyDeviceSuggestionsUpdated(suggestingPackageName, suggestedDeviceInfo);
        }

        private void onRequestFailedOnHandler(int requestId, int reason) {
            MediaRouter2Manager.TransferRequest matchingRequest = null;
            for (MediaRouter2Manager.TransferRequest request : mTransferRequests) {
@@ -3389,6 +3577,20 @@ public final class MediaRouter2 {
                                routeListingPreference));
            }

            @Override
            public void notifyDeviceSuggestionsUpdated(
                    String packageName,
                    String suggestingPackageName,
                    @Nullable List<SuggestedDeviceInfo> deviceSuggestions) {
                mHandler.sendMessage(
                        obtainMessage(
                                ProxyMediaRouter2Impl::onDeviceSuggestionsChangeHandler,
                                ProxyMediaRouter2Impl.this,
                                packageName,
                                suggestingPackageName,
                                deviceSuggestions));
            }

            @Override
            public void notifyRoutesUpdated(List<MediaRoute2Info> routes) {
                mHandler.sendMessage(
@@ -3552,6 +3754,30 @@ public final class MediaRouter2 {
            }
        }

        @Override
        public void setDeviceSuggestions(@Nullable List<SuggestedDeviceInfo> deviceSuggestions) {
            synchronized (mLock) {
                try {
                    registerRouterStubIfNeededLocked();
                    mMediaRouterService.setDeviceSuggestionsWithRouter2(mStub, deviceSuggestions);
                } catch (RemoteException ex) {
                    ex.rethrowFromSystemServer();
                }
            }
        }

        @Override
        @Nullable
        public Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestions() {
            synchronized (mLock) {
                try {
                    return mMediaRouterService.getDeviceSuggestionsWithRouter2(mStub);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
        }

        @Override
        public boolean showSystemOutputSwitcher() {
            synchronized (mLock) {
+8 −0
Original line number Diff line number Diff line
@@ -1137,6 +1137,14 @@ public final class MediaRouter2Manager {
                            routeListingPreference));
        }

        @Override
        public void notifyDeviceSuggestionsUpdated(
                String packageName,
                String suggestingPackageName,
                @Nullable List<SuggestedDeviceInfo> suggestedDeviceInfo) {
            // MediaRouter2Manager doesn't support device suggestions
        }

        @Override
        public void notifyRoutesUpdated(List<MediaRoute2Info> routes) {
            mHandler.sendMessage(
Loading