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

Commit dd4780eb authored by Hyundo Moon's avatar Hyundo Moon
Browse files

Add basic functionality of MR2Manager in MR2

As a first step of adding MR2Manager functionality in MR2,
this CL makes MR2 able to:
 - get routes for specific package
 - make transfer / stop

For now, the future system APIs are not marked as @SystemApi yet.
They will be opened with adding CTS tests,
once the implementation is complete.

Bug: 181122201
Test: Manually tested transfer/stop using Support7Demos.
      Test code will be added when MR2Manager's callback functionality
      is implemented.
Change-Id: I71bea98b0ff3e42d193cf04c1b1735fe50c7d673
parent 7e3f7d10
Loading
Loading
Loading
Loading
+97 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -66,6 +67,10 @@ public final class MediaRouter2 {
    // The manager request ID representing that no manager is involved.
    private static final long MANAGER_REQUEST_ID_NONE = MediaRoute2ProviderService.REQUEST_ID_NONE;

    @GuardedBy("sRouterLock")
    private static Map<String, MediaRouter2> sMediaRouter2Map = new ArrayMap<>();
    private static MediaRouter2Manager sManager;

    @GuardedBy("sRouterLock")
    private static MediaRouter2 sInstance;

@@ -82,7 +87,9 @@ public final class MediaRouter2 {
    private final CopyOnWriteArrayList<ControllerCreationRequest> mControllerCreationRequests =
            new CopyOnWriteArrayList<>();

    private final String mClientPackageName;
    private final String mPackageName;

    @GuardedBy("sRouterLock")
    final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>();

@@ -120,6 +127,42 @@ public final class MediaRouter2 {
        }
    }

    /**
     * Gets an instance of the media router which controls the app's media routing.
     * Returns {@code null} if the given package name is invalid.
     *
     * @param clientPackageName the package name of the app to control
     * @hide
     */
    //@SystemApi
    @Nullable
    public static MediaRouter2 getInstance(@NonNull Context context,
            @NonNull String clientPackageName) {
        Objects.requireNonNull(context, "context must not be null");
        Objects.requireNonNull(clientPackageName, "clientPackageName must not be null");

        PackageManager pm = context.getPackageManager();
        try {
            pm.getPackageInfo(clientPackageName, 0);
        } catch (PackageManager.NameNotFoundException ex) {
            Log.e(TAG, "Package " + clientPackageName + " not found. Ignoring.");
            return null;
        }

        synchronized (sRouterLock) {
            MediaRouter2 instance = sMediaRouter2Map.get(clientPackageName);
            if (instance == null) {
                // TODO: Add permission check here using MODIFY_AUDIO_ROUTING.
                if (sManager == null) {
                    sManager = MediaRouter2Manager.getInstance(context.getApplicationContext());
                }
                instance = new MediaRouter2(context, clientPackageName);
                sMediaRouter2Map.put(clientPackageName, instance);
            }
            return instance;
        }
    }

    private MediaRouter2(Context appContext) {
        mContext = appContext;
        mMediaRouterService = IMediaRouterService.Stub.asInterface(
@@ -148,6 +191,17 @@ public final class MediaRouter2 {
            mRoutes.put(route.getId(), route);
        }
        mSystemController = new SystemRoutingController(currentSystemSessionInfo);

        mClientPackageName = null;
    }

    private MediaRouter2(Context context, String clientPackageName) {
        mClientPackageName = clientPackageName;
        mContext = context;
        mMediaRouterService = null;
        mPackageName = null;
        mHandler = new Handler(Looper.getMainLooper());
        mSystemController = null;
    }

    /**
@@ -165,6 +219,19 @@ public final class MediaRouter2 {
        return false;
    }

    /**
     * Gets the target package name of the app which this media router controls.
     * This is only non-null when the router instance is created with the target package name.
     *
     * @see #getInstance(Context, String)
     * @hide
     */
    //@SystemApi
    @Nullable
    public String getClientPackageName() {
        return mClientPackageName;
    }

    /**
     * Registers a callback to discover routes and to receive events when they change.
     * <p>
@@ -270,6 +337,10 @@ public final class MediaRouter2 {
     */
    @NonNull
    public List<MediaRoute2Info> getRoutes() {
        if (mClientPackageName != null) {
            return sManager.getAvailableRoutes(mClientPackageName);
        }

        synchronized (sRouterLock) {
            if (mShouldUpdateRoutes) {
                mShouldUpdateRoutes = false;
@@ -378,6 +449,11 @@ public final class MediaRouter2 {
     * @see TransferCallback#onTransferFailure
     */
    public void transferTo(@NonNull MediaRoute2Info route) {
        if (mClientPackageName != null) {
            sManager.selectRoute(mClientPackageName, route);
            return;
        }

        Objects.requireNonNull(route, "route must not be null");
        Log.v(TAG, "Transferring to route: " + route);
        transfer(getCurrentController(), route);
@@ -388,6 +464,12 @@ public final class MediaRouter2 {
     * controls the media routing, this method is a no-op.
     */
    public void stop() {
        if (mClientPackageName != null) {
            List<RoutingSessionInfo> sessionInfos = sManager.getRoutingSessions(mClientPackageName);
            RoutingSessionInfo sessionToRelease = sessionInfos.get(sessionInfos.size() - 1);
            sManager.releaseSession(sessionToRelease);
            return;
        }
        getCurrentController().release();
    }

@@ -397,7 +479,13 @@ public final class MediaRouter2 {
     * @param route the route you want to transfer the media to.
     * @hide
     */
    void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
    //@SystemApi
    public void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
        if (mClientPackageName != null) {
            sManager.transfer(controller.getRoutingSessionInfo(), route);
            return;
        }

        Objects.requireNonNull(controller, "controller must not be null");
        Objects.requireNonNull(route, "route must not be null");

@@ -486,6 +574,14 @@ public final class MediaRouter2 {
     */
    @NonNull
    public List<RoutingController> getControllers() {
        // TODO: Do not create the controller instances every time,
        //       Instead, update the list using the sessions' ID and session related callbacks.
        if (mClientPackageName != null) {
            return sManager.getRoutingSessions(mClientPackageName).stream()
                    .map(info -> new RoutingController(info))
                    .collect(Collectors.toList());
        }

        List<RoutingController> result = new ArrayList<>();
        result.add(0, mSystemController);
        synchronized (sRouterLock) {
+1 −0
Original line number Diff line number Diff line
@@ -326,6 +326,7 @@ public final class RoutingSessionInfo implements Parcelable {
                .append("RoutingSessionInfo{ ")
                .append("sessionId=").append(getId())
                .append(", name=").append(getName())
                .append(", clientPackageName=").append(getClientPackageName())
                .append(", selectedRoutes={")
                .append(String.join(",", getSelectedRoutes()))
                .append("}")