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

Commit bf27c6be authored by Kyunglyul Hyun's avatar Kyunglyul Hyun Committed by Automerger Merge Worker
Browse files

Merge "Use session hints when create a session from MR2Manager" into rvc-dev...

Merge "Use session hints when create a session from MR2Manager" into rvc-dev am: e66ac51e am: b529c1c2 am: 412b682f am: 4092146c

Change-Id: Ib4ca4833b0b7012ce1278f10ff4f4cd31cbe47ad
parents 81ebe3dc 4092146c
Loading
Loading
Loading
Loading
+5 −1
Original line number Original line Diff line number Diff line
@@ -24,11 +24,15 @@ import android.os.Bundle;
 * @hide
 * @hide
 */
 */
oneway interface IMediaRouter2 {
oneway interface IMediaRouter2 {
    void notifyRestoreRoute();
    void notifyRoutesAdded(in List<MediaRoute2Info> routes);
    void notifyRoutesAdded(in List<MediaRoute2Info> routes);
    void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
    void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
    void notifyRoutesChanged(in List<MediaRoute2Info> routes);
    void notifyRoutesChanged(in List<MediaRoute2Info> routes);
    void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo);
    void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo);
    void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo);
    void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo);
    void notifySessionReleased(in RoutingSessionInfo sessionInfo);
    void notifySessionReleased(in RoutingSessionInfo sessionInfo);
    /**
     * Gets hints of the new session for the given route.
     * Call MediaRouterService#notifySessionHintsForCreatingSession to pass the result.
     */
    void getSessionHintsForCreatingSession(long uniqueRequestId, in MediaRoute2Info route);
}
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -59,6 +59,8 @@ interface IMediaRouterService {


    void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
    void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
            in MediaRoute2Info route, in @nullable Bundle sessionHints);
            in MediaRoute2Info route, in @nullable Bundle sessionHints);
    void notifySessionHintsForCreatingSession(IMediaRouter2 router, long uniqueRequestId,
                in MediaRoute2Info route, in @nullable Bundle sessionHints);
    void selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
    void selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
    void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
    void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
    void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId,
    void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId,
+39 −8
Original line number Original line Diff line number Diff line
@@ -690,6 +690,31 @@ public final class MediaRouter2 {
        matchingController.releaseInternal(/* shouldReleaseSession= */ false);
        matchingController.releaseInternal(/* shouldReleaseSession= */ false);
    }
    }


    void onGetControllerHintsForCreatingSessionOnHandler(long uniqueRequestId,
            MediaRoute2Info route) {
        OnGetControllerHintsListener listener = mOnGetControllerHintsListener;
        Bundle controllerHints = null;
        if (listener != null) {
            controllerHints = listener.onGetControllerHints(route);
            if (controllerHints != null) {
                controllerHints = new Bundle(controllerHints);
            }
        }

        MediaRouter2Stub stub;
        synchronized (sRouterLock) {
            stub = mStub;
        }
        if (stub != null) {
            try {
                mMediaRouterService.notifySessionHintsForCreatingSession(
                        stub, uniqueRequestId, route, controllerHints);
            } catch (RemoteException ex) {
                Log.e(TAG, "getSessionHintsOnHandler: Unable to request.", ex);
            }
        }
    }

    private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
    private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
            RouteDiscoveryPreference discoveryRequest) {
            RouteDiscoveryPreference discoveryRequest) {
        return routes.stream()
        return routes.stream()
@@ -820,13 +845,14 @@ public final class MediaRouter2 {
     */
     */
    public interface OnGetControllerHintsListener {
    public interface OnGetControllerHintsListener {
        /**
        /**
         * Called when the {@link MediaRouter2} is about to request
         * Called when the {@link MediaRouter2} or the system is about to request
         * the media route provider service to create a controller with the given route.
         * a media route provider service to create a controller with the given route.
         * The {@link Bundle} returned here will be sent to media route provider service as a hint.
         * The {@link Bundle} returned here will be sent to media route provider service as a hint.
         * <p>
         * <p>
         * To send hints when creating the controller, set the listener before calling
         * Since controller creation can be requested by the {@link MediaRouter2} and the system,
         * {@link #transferTo(MediaRoute2Info)}. The method will be called
         * set the listener as soon as possible after acquiring {@link MediaRouter2} instance.
         * on the same thread which calls {@link #transferTo(MediaRoute2Info)}.
         * The method will be called on the same thread that calls
         * {@link #transferTo(MediaRoute2Info)} or the main thread if it is requested by the system.
         *
         *
         * @param route The route to create controller with
         * @param route The route to create controller with
         * @return An optional bundle of app-specific arguments to send to the provider,
         * @return An optional bundle of app-specific arguments to send to the provider,
@@ -1377,9 +1403,6 @@ public final class MediaRouter2 {
    }
    }


    class MediaRouter2Stub extends IMediaRouter2.Stub {
    class MediaRouter2Stub extends IMediaRouter2.Stub {
        @Override
        public void notifyRestoreRoute() throws RemoteException {}

        @Override
        @Override
        public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
        public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
            mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler,
            mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler,
@@ -1415,5 +1438,13 @@ public final class MediaRouter2 {
            mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler,
            mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler,
                    MediaRouter2.this, sessionInfo));
                    MediaRouter2.this, sessionInfo));
        }
        }

        @Override
        public void getSessionHintsForCreatingSession(long uniqueRequestId,
                @NonNull MediaRoute2Info route) {
            mHandler.sendMessage(obtainMessage(
                    MediaRouter2::onGetControllerHintsForCreatingSessionOnHandler,
                    MediaRouter2.this, uniqueRequestId, route));
        }
    }
    }
}
}
+53 −0
Original line number Original line Diff line number Diff line
@@ -48,6 +48,7 @@ import android.media.MediaRouter2Manager;
import android.media.MediaRouter2Utils;
import android.media.MediaRouter2Utils;
import android.media.RouteDiscoveryPreference;
import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.AndroidJUnit4;
@@ -74,6 +75,8 @@ public class MediaRouter2ManagerTest {
    private static final String TAG = "MediaRouter2ManagerTest";
    private static final String TAG = "MediaRouter2ManagerTest";
    private static final int WAIT_TIME_MS = 2000;
    private static final int WAIT_TIME_MS = 2000;
    private static final int TIMEOUT_MS = 5000;
    private static final int TIMEOUT_MS = 5000;
    private static final String TEST_KEY = "test_key";
    private static final String TEST_VALUE = "test_value";


    private Context mContext;
    private Context mContext;
    private MediaRouter2Manager mManager;
    private MediaRouter2Manager mManager;
@@ -513,6 +516,56 @@ public class MediaRouter2ManagerTest {
        assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
        assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
    }
    }


    @Test
    public void testRouter2SetOnGetControllerHintsListener() throws Exception {
        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
        addRouterCallback(new RouteCallback() {});

        MediaRoute2Info route = routes.get(ROUTE_ID1);
        assertNotNull(route);

        final Bundle controllerHints = new Bundle();
        controllerHints.putString(TEST_KEY, TEST_VALUE);
        final CountDownLatch hintLatch = new CountDownLatch(1);
        final MediaRouter2.OnGetControllerHintsListener listener =
                route1 -> {
                    hintLatch.countDown();
                    return controllerHints;
                };

        final CountDownLatch successLatch = new CountDownLatch(1);
        final CountDownLatch failureLatch = new CountDownLatch(1);

        addManagerCallback(new MediaRouter2Manager.Callback() {
            @Override
            public void onTransferred(RoutingSessionInfo oldSession,
                    RoutingSessionInfo newSession) {
                assertTrue(newSession.getSelectedRoutes().contains(route.getId()));
                // The StubMediaRoute2ProviderService is supposed to set control hints
                // with the given controllerHints.
                Bundle controlHints = newSession.getControlHints();
                assertNotNull(controlHints);
                assertTrue(controlHints.containsKey(TEST_KEY));
                assertEquals(TEST_VALUE, controlHints.getString(TEST_KEY));

                successLatch.countDown();
            }

            @Override
            public void onTransferFailed(RoutingSessionInfo session,
                    MediaRoute2Info requestedRoute) {
                failureLatch.countDown();
            }
        });

        mRouter2.setOnGetControllerHintsListener(listener);
        mManager.selectRoute(mPackageName, route);
        assertTrue(hintLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
        assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));

        assertFalse(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
    }

    Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
    Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
            throws Exception {
            throws Exception {
        CountDownLatch addedLatch = new CountDownLatch(1);
        CountDownLatch addedLatch = new CountDownLatch(1);
+101 −11
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package com.android.server.media;
package com.android.server.media;


import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
import static android.media.MediaRouter2Utils.getProviderId;
@@ -247,6 +249,22 @@ class MediaRouter2ServiceImpl {
        }
        }
    }
    }


    public void notifySessionHintsForCreatingSession(IMediaRouter2 router,
            long uniqueRequestId, MediaRoute2Info route, Bundle sessionHints) {
        Objects.requireNonNull(router, "router must not be null");
        Objects.requireNonNull(route, "route must not be null");

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                notifySessionHintsForCreatingSessionLocked(uniqueRequestId,
                        router, route, sessionHints);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
    public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
            MediaRoute2Info route) {
            MediaRoute2Info route) {
        Objects.requireNonNull(router, "router must not be null");
        Objects.requireNonNull(router, "router must not be null");
@@ -265,7 +283,6 @@ class MediaRouter2ServiceImpl {
        }
        }
    }
    }



    public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
    public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
            MediaRoute2Info route) {
            MediaRoute2Info route) {
        Objects.requireNonNull(router, "router must not be null");
        Objects.requireNonNull(router, "router must not be null");
@@ -634,12 +651,30 @@ class MediaRouter2ServiceImpl {


        long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
        long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
        routerRecord.mUserRecord.mHandler.sendMessage(
        routerRecord.mUserRecord.mHandler.sendMessage(
                obtainMessage(UserHandler::requestCreateSessionOnHandler,
                obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler,
                        routerRecord.mUserRecord.mHandler,
                        routerRecord.mUserRecord.mHandler,
                        uniqueRequestId, routerRecord, /* managerRecord= */ null, route,
                        uniqueRequestId, routerRecord, route,
                        sessionHints));
                        sessionHints));
    }
    }


    private void notifySessionHintsForCreatingSessionLocked(long uniqueRequestId,
            @NonNull IMediaRouter2 router,
            @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
        final IBinder binder = router.asBinder();
        final RouterRecord routerRecord = mAllRouterRecords.get(binder);

        if (routerRecord == null) {
            Slog.w(TAG, "requestCreateSessionWithRouter2ByManagerRequestLocked: "
                    + "Ignoring unknown router.");
            return;
        }

        routerRecord.mUserRecord.mHandler.sendMessage(
                obtainMessage(UserHandler::requestCreateSessionWithManagerOnHandler,
                        routerRecord.mUserRecord.mHandler,
                        uniqueRequestId, routerRecord, route, sessionHints));
    }

    private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
    private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
        final IBinder binder = router.asBinder();
        final IBinder binder = router.asBinder();
@@ -826,12 +861,13 @@ class MediaRouter2ServiceImpl {
        }
        }


        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
        //TODO(b/152851868): Use MediaRouter2's OnCreateSessionListener to send session hints.

        // Before requesting to the provider, get session hints from the media router.
        // As a return, media router will request to create a session.
        routerRecord.mUserRecord.mHandler.sendMessage(
        routerRecord.mUserRecord.mHandler.sendMessage(
                obtainMessage(UserHandler::requestCreateSessionOnHandler,
                obtainMessage(UserHandler::getSessionHintsForCreatingSessionOnHandler,
                        routerRecord.mUserRecord.mHandler,
                        routerRecord.mUserRecord.mHandler,
                        uniqueRequestId, routerRecord, managerRecord, route,
                        uniqueRequestId, routerRecord, managerRecord, route));
                        /* sessionHints= */ null));
    }
    }


    private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
    private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
@@ -1149,7 +1185,6 @@ class MediaRouter2ServiceImpl {
                    this, provider, uniqueRequestId, sessionInfo));
                    this, provider, uniqueRequestId, sessionInfo));
        }
        }



        @Override
        @Override
        public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
        public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo) {
                @NonNull RoutingSessionInfo sessionInfo) {
@@ -1267,8 +1302,26 @@ class MediaRouter2ServiceImpl {
            return -1;
            return -1;
        }
        }


        private void requestCreateSessionOnHandler(long uniqueRequestId,
        private void getSessionHintsForCreatingSessionOnHandler(long uniqueRequestId,
                @NonNull RouterRecord routerRecord, @Nullable ManagerRecord managerRecord,
                @NonNull RouterRecord routerRecord, @NonNull ManagerRecord managerRecord,
                @NonNull MediaRoute2Info route) {
            SessionCreationRequest request =
                    new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord);
            mSessionCreationRequests.add(request);

            try {
                routerRecord.mRouter.getSessionHintsForCreatingSession(uniqueRequestId, route);
            } catch (RemoteException ex) {
                Slog.w(TAG, "requestGetSessionHintsOnHandler: "
                        + "Failed to request. Router probably died.");
                mSessionCreationRequests.remove(request);
                notifyRequestFailedToManager(managerRecord.mManager,
                        toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
            }
        }

        private void requestCreateSessionWithRouter2OnHandler(long uniqueRequestId,
                @NonNull RouterRecord routerRecord,
                @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
                @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {


            final MediaRoute2Provider provider = findProvider(route.getProviderId());
            final MediaRoute2Provider provider = findProvider(route.getProviderId());
@@ -1281,13 +1334,50 @@ class MediaRouter2ServiceImpl {
            }
            }


            SessionCreationRequest request =
            SessionCreationRequest request =
                    new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord);
                    new SessionCreationRequest(routerRecord, uniqueRequestId, route, null);
            mSessionCreationRequests.add(request);
            mSessionCreationRequests.add(request);


            provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
            provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
                    route.getOriginalId(), sessionHints);
                    route.getOriginalId(), sessionHints);
        }
        }


        private void requestCreateSessionWithManagerOnHandler(long uniqueRequestId,
                @NonNull RouterRecord routerRecord,
                @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
            SessionCreationRequest matchingRequest = null;
            for (SessionCreationRequest request : mSessionCreationRequests) {
                if (request.mUniqueRequestId == uniqueRequestId) {
                    matchingRequest = request;
                    break;
                }
            }
            if (matchingRequest == null) {
                Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
                        + "Ignoring an unknown request.");
                return;
            }

            if (!TextUtils.equals(matchingRequest.mRoute.getId(), route.getId())) {
                Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
                        + "The given route is different from the requested route.");
                return;
            }

            final MediaRoute2Provider provider = findProvider(route.getProviderId());
            if (provider == null) {
                Slog.w(TAG, "Ignoring session creation request since no provider found for"
                        + " given route=" + route);

                mSessionCreationRequests.remove(matchingRequest);
                notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
                        toOriginalRequestId(uniqueRequestId), REASON_ROUTE_NOT_AVAILABLE);
                return;
            }

            provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
                    route.getOriginalId(), sessionHints);
        }

        // routerRecord can be null if the session is system's or RCN.
        // routerRecord can be null if the session is system's or RCN.
        private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
        private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Loading