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

Commit f7d5e044 authored by Kyunglyul Hyun's avatar Kyunglyul Hyun
Browse files

MediaRouter: send control hints from provider to client

This CL enables providers to send control hints to the clients
so connections can be established between clients and providers.

This CL also adds a hidden flag such that MR2 can notice whether
the route is selected by itself or MR2Manager.

Uses of Mockito is completely removed from the test for better test
environment.

Callbacks will be unregistered automatically when a test is
ended so there will be no unregistered callbacks remaining after
test failures.

Test: atest mediaroutertest
Change-Id: I1411bad3ddd7890fbf76020107f870daa2413077
parent 3ef13e04
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -17,10 +17,13 @@
package android.media;

import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2Info;
import android.os.Bundle;

/**
 * @hide
 */
oneway interface IMediaRoute2ProviderClient {
    void updateProviderInfo(in MediaRoute2ProviderInfo info);
    void notifyRouteSelected(String packageName, String routeId, in Bundle controlHints, int seq);
}
+60 −9
Original line number Diff line number Diff line
@@ -18,14 +18,19 @@ package android.media;

import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;

import java.util.Objects;

/**
 * @hide
 */
@@ -44,7 +49,7 @@ public abstract class MediaRoute2ProviderService extends Service {
    }

    @Override
    public IBinder onBind(Intent intent) {
    public IBinder onBind(@NonNull Intent intent) {
        //TODO: Allow binding from media router service only?
        if (SERVICE_INTERFACE.equals(intent.getAction())) {
            if (mStub == null) {
@@ -57,11 +62,17 @@ public abstract class MediaRoute2ProviderService extends Service {

    /**
     * Called when selectRoute is called on a route of the provider.
     * Once the route is ready to be used , call {@link #notifyRouteSelected(SelectToken, Bundle)}
     * to notify that.
     *
     * @param packageName the package name of the application that selected the route
     * @param routeId the id of the route being selected
     * @param token token that contains select info
     *
     * @see #notifyRouteSelected
     */
    public abstract void onSelectRoute(String packageName, String routeId);
    public abstract void onSelectRoute(@NonNull String packageName, @NonNull String routeId,
            @NonNull SelectToken token);

    /**
     * Called when unselectRoute is called on a route of the provider.
@@ -69,7 +80,7 @@ public abstract class MediaRoute2ProviderService extends Service {
     * @param packageName the package name of the application that has selected the route.
     * @param routeId the id of the route being unselected
     */
    public abstract void onUnselectRoute(String packageName, String routeId);
    public abstract void onUnselectRoute(@NonNull String packageName, @NonNull String routeId);

    /**
     * Called when sendControlRequest is called on a route of the provider
@@ -78,21 +89,21 @@ public abstract class MediaRoute2ProviderService extends Service {
     * @param request the media control request intent
     */
    //TODO: Discuss what to use for request (e.g., Intent? Request class?)
    public abstract void onControlRequest(String routeId, Intent request);
    public abstract void onControlRequest(@NonNull String routeId, @NonNull Intent request);

    /**
     * Called when requestSetVolume is called on a route of the provider
     * @param routeId the id of the route
     * @param volume the target volume
     */
    public abstract void onSetVolume(String routeId, int volume);
    public abstract void onSetVolume(@NonNull String routeId, int volume);

    /**
     * Called when requestUpdateVolume is called on a route of the provider
     * @param routeId id of the route
     * @param delta the delta to add to the current volume
     */
    public abstract void onUpdateVolume(String routeId, int delta);
    public abstract void onUpdateVolume(@NonNull String routeId, int delta);

    /**
     * Updates provider info and publishes routes
@@ -102,6 +113,29 @@ public abstract class MediaRoute2ProviderService extends Service {
        publishState();
    }

    /**
     * Notifies the client of that the selected route is ready for use. If the selected route can be
     * controlled, pass a {@link Bundle} that contains how to control it.
     *
     * @param token token passed in {@link #onSelectRoute}
     * @param controlHints a {@link Bundle} that contains how to control the given route.
     * Pass {@code null} if the route is not available.
     */
    public final void notifyRouteSelected(@NonNull SelectToken token,
            @Nullable Bundle controlHints) {
        Objects.requireNonNull(token, "token must not be null");

        if (mClient == null) {
            return;
        }
        try {
            mClient.notifyRouteSelected(token.mPackageName, token.mRouteId,
                    controlHints, token.mSeq);
        } catch (RemoteException ex) {
            Log.w(TAG, "Failed to notify route selected");
        }
    }

    void setClient(IMediaRoute2ProviderClient client) {
        mClient = client;
        publishState();
@@ -118,6 +152,23 @@ public abstract class MediaRoute2ProviderService extends Service {
        }
    }

    /**
     * Route selection information.
     *
     * @see #notifyRouteSelected
     */
    public final class SelectToken {
        final String mPackageName;
        final String mRouteId;
        final int mSeq;

        SelectToken(String packageName, String routeId, int seq) {
            mPackageName = packageName;
            mRouteId = routeId;
            mSeq = seq;
        }
    }

    final class ProviderStub extends IMediaRoute2Provider.Stub {
        ProviderStub() { }

@@ -129,10 +180,10 @@ public abstract class MediaRoute2ProviderService extends Service {

        @Override
        public void requestSelectRoute(String packageName, String id, int seq) {
            // TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
            // use the sequence number here properly.
            mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
                    MediaRoute2ProviderService.this, packageName, id));
                    MediaRoute2ProviderService.this, packageName, id,
                    new SelectToken(packageName, id, seq)));

        }

        @Override
+1 −0
Original line number Diff line number Diff line
@@ -1318,6 +1318,7 @@ public class MediaRouter {
        sStatic.rebindAsUser(userId);
    }

    //TODO: remove this and Client1Record in MediaRouter2ServiceImpl.
    /**
     * Sets the control categories of the application.
     * Routes that support at least one of the given control categories only exists and are handled
+12 −1
Original line number Diff line number Diff line
@@ -57,7 +57,8 @@ public class MediaRouter2 {
    @IntDef(value = {
            SELECT_REASON_UNKNOWN,
            SELECT_REASON_USER_SELECTED,
            SELECT_REASON_FALLBACK})
            SELECT_REASON_FALLBACK,
            SELECT_REASON_SYSTEM_SELECTED})
    public @interface SelectReason {}

    /**
@@ -80,6 +81,13 @@ public class MediaRouter2 {
     */
    public static final int SELECT_REASON_FALLBACK = 2;

    /**
     * This is passed from {@link com.android.server.media.MediaRouterService} when the route
     * is selected in response to a request from other apps (e.g. System UI).
     * @hide
     */
    public static final int SELECT_REASON_SYSTEM_SELECTED = 3;

    private static final String TAG = "MR2";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    private static final Object sLock = new Object();
@@ -485,6 +493,9 @@ public class MediaRouter2 {
            }
            mSelectingRoute = null;
        }
        if (reason == SELECT_REASON_SYSTEM_SELECTED) {
            reason = SELECT_REASON_USER_SELECTED;
        }
        mSelectedRoute = route;
        notifyRouteSelected(route, reason, controlHints);
    }
+3 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
import android.os.Bundle;
import android.os.IBinder;

import java.util.HashMap;
@@ -95,7 +96,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
    }

    @Override
    public void onSelectRoute(String packageName, String routeId) {
    public void onSelectRoute(String packageName, String routeId, SelectToken token) {
        MediaRoute2Info route = mRoutes.get(routeId);
        if (route == null) {
            return;
@@ -104,6 +105,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
                .setClientPackageName(packageName)
                .build());
        publishRoutes();
        notifyRouteSelected(token, Bundle.EMPTY);
    }

    @Override
Loading