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

Commit cf678431 authored by Iván Budnik's avatar Iván Budnik
Browse files

Add support for showing Output Switcher from proxy routers

Also, simplify logic for launching output switcher.

Bug: 344843445
Test: atest CtsMediaBetterTogetherTestCases
Flag: EXEMPT Minimal logic addition with no usages.
Change-Id: Ibd7d7ecbecb7356fb486f94c3a7a94d1a9946881
parent bc9ebd96
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ interface IMediaRouterService {
    // Methods for MediaRouter2
    List<MediaRoute2Info> getSystemRoutes(String callerPackageName, boolean isProxyRouter);
    RoutingSessionInfo getSystemSessionInfo();
    boolean showMediaOutputSwitcherWithRouter2(String packageName);

    void registerRouter2(IMediaRouter2 router, String packageName);
    void unregisterRouter2(IMediaRouter2 router);
@@ -97,5 +98,5 @@ interface IMediaRouterService {
    void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
            String sessionId, int volume);
    void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId, String sessionId);
    boolean showMediaOutputSwitcher(String packageName);
    boolean showMediaOutputSwitcherWithProxyRouter(IMediaRouter2Manager manager);
}
+6 −3
Original line number Diff line number Diff line
@@ -2666,8 +2666,11 @@ public final class MediaRouter2 {

        @Override
        public boolean showSystemOutputSwitcher() {
            throw new UnsupportedOperationException(
                    "Cannot show system output switcher from a privileged router.");
            try {
                return mMediaRouterService.showMediaOutputSwitcherWithProxyRouter(mClient);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }

        /** Gets the list of all discovered routes. */
@@ -3539,7 +3542,7 @@ public final class MediaRouter2 {
        public boolean showSystemOutputSwitcher() {
            synchronized (mLock) {
                try {
                    return mMediaRouterService.showMediaOutputSwitcher(mImpl.getPackageName());
                    return mMediaRouterService.showMediaOutputSwitcherWithRouter2(mPackageName);
                } catch (RemoteException ex) {
                    ex.rethrowFromSystemServer();
                }
+52 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.media.flags.Flags;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;

import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -118,6 +119,7 @@ class MediaRouter2ServiceImpl {
    private final UserManagerInternal mUserManagerInternal;
    private final Object mLock = new Object();
    private final AppOpsManager mAppOpsManager;
    private final StatusBarManagerInternal mStatusBarManagerInternal;
    final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
    final ActivityManager mActivityManager;
    final PowerManager mPowerManager;
@@ -188,6 +190,7 @@ class MediaRouter2ServiceImpl {
        mPowerManager = mContext.getSystemService(PowerManager.class);
        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
        mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);

        IntentFilter screenOnOffIntentFilter = new IntentFilter();
        screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON);
@@ -260,6 +263,17 @@ class MediaRouter2ServiceImpl {
        }
    }

    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
    public boolean showMediaOutputSwitcherWithRouter2(@NonNull String packageName) {
        UserHandle userHandle = Binder.getCallingUserHandle();
        final long token = Binder.clearCallingIdentity();
        try {
            return showOutputSwitcher(packageName, userHandle);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    public void registerRouter2(@NonNull IMediaRouter2 router, @NonNull String packageName) {
        Objects.requireNonNull(router, "router must not be null");
        if (TextUtils.isEmpty(packageName)) {
@@ -778,6 +792,31 @@ class MediaRouter2ServiceImpl {
        }
    }

    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
    public boolean showMediaOutputSwitcherWithProxyRouter(
            @NonNull IMediaRouter2Manager proxyRouter) {
        Objects.requireNonNull(proxyRouter, "Proxy router must not be null");

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                final IBinder binder = proxyRouter.asBinder();
                ManagerRecord proxyRouterRecord = mAllManagerRecords.get(binder);

                if (proxyRouterRecord.mTargetPackageName == null) {
                    throw new UnsupportedOperationException(
                            "Only proxy routers can show the Output Switcher.");
                }

                return showOutputSwitcher(
                        proxyRouterRecord.mTargetPackageName,
                        UserHandle.of(proxyRouterRecord.mUserRecord.mUserId));
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    // End of methods that implement MediaRouter2Manager operations.

    // Start of methods that implements operations for both MediaRouter2 and MediaRouter2Manager.
@@ -934,6 +973,19 @@ class MediaRouter2ServiceImpl {
        }
    }

    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
    private boolean showOutputSwitcher(
            @NonNull String packageName, @NonNull UserHandle userHandle) {
        if (mActivityManager.getPackageImportance(packageName) > IMPORTANCE_FOREGROUND) {
            Slog.w(TAG, "showMediaOutputSwitcher only works when called from foreground");
            return false;
        }
        synchronized (mLock) {
            mStatusBarManagerInternal.showMediaOutputSwitcher(packageName, userHandle);
        }
        return true;
    }

    // End of methods that implements operations for both MediaRouter2 and MediaRouter2Manager.

    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+18 −28
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.media;

import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

import android.Manifest;
import android.annotation.NonNull;
@@ -75,7 +74,6 @@ import com.android.media.flags.Flags;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
import com.android.server.pm.UserManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -264,32 +262,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        }
    }

    // Binder call
    @Override
    public boolean showMediaOutputSwitcher(String packageName) {
        int uid = Binder.getCallingUid();
        if (!validatePackageName(uid, packageName)) {
            throw new SecurityException("packageName must match the calling identity");
        }
        UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
        final long token = Binder.clearCallingIdentity();
        try {
            if (mContext.getSystemService(ActivityManager.class).getPackageImportance(packageName)
                    > IMPORTANCE_FOREGROUND) {
                Slog.w(TAG, "showMediaOutputSwitcher only works when called from foreground");
                return false;
            }
            synchronized (mLock) {
                StatusBarManagerInternal statusBar =
                        LocalServices.getService(StatusBarManagerInternal.class);
                statusBar.showMediaOutputSwitcher(packageName, userHandle);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        return true;
    }

    // Binder call
    @Override
    public MediaRouterClientState getState(IMediaRouterClient client) {
@@ -442,6 +414,17 @@ public final class MediaRouterService extends IMediaRouterService.Stub
                false);
    }

    // Binder call
    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
    @Override
    public boolean showMediaOutputSwitcherWithRouter2(@NonNull String packageName) {
        int uid = Binder.getCallingUid();
        if (!validatePackageName(uid, packageName)) {
            throw new SecurityException("packageName must match the calling identity");
        }
        return mService2.showMediaOutputSwitcherWithRouter2(packageName);
    }

    // Binder call
    @Override
    public void registerRouter2(IMediaRouter2 router, String packageName) {
@@ -676,6 +659,13 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        mService2.releaseSessionWithManager(manager, requestId, sessionId);
    }

    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
    @Override
    public boolean showMediaOutputSwitcherWithProxyRouter(
            @NonNull IMediaRouter2Manager proxyRouter) {
        return mService2.showMediaOutputSwitcherWithProxyRouter(proxyRouter);
    }

    void restoreBluetoothA2dp() {
        try {
            boolean a2dpOn;