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

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

Allow registering multiple RemoteVolumeController

Bug: 126890783
Test: flashed and change volume while casting
Change-Id: I6e0624161c29f9d4d81ade218d3bcfb2a0429351
parent cb0da694
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -55,8 +55,8 @@ interface ISessionManager {
    void addSession2TokensListener(in ISession2TokensListener listener, int userId);
    void removeSession2TokensListener(in ISession2TokensListener listener);

    // This is for the system volume UI only
    void setRemoteVolumeController(in IRemoteVolumeController rvc);
    void registerRemoteVolumeController(in IRemoteVolumeController rvc);
    void unregisterRemoteVolumeController(in IRemoteVolumeController rvc);

    // For PhoneWindowManager to precheck media keys
    boolean isGlobalPriorityActive();
+21 −5
Original line number Diff line number Diff line
@@ -424,17 +424,33 @@ public final class MediaSessionManager {
    }

    /**
     * Set the remote volume controller to receive volume updates on. Only for
     * use by system UI.
     * Set the remote volume controller to receive volume updates on.
     * Only for use by System UI and Settings application.
     *
     * @param rvc The volume controller to receive updates on.
     * @hide
     */
    public void setRemoteVolumeController(IRemoteVolumeController rvc) {
    public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
        try {
            mService.setRemoteVolumeController(rvc);
            mService.registerRemoteVolumeController(rvc);
        } catch (RemoteException e) {
            Log.e(TAG, "Error in setRemoteVolumeController.", e);
            Log.e(TAG, "Error in registerRemoteVolumeController.", e);
        }
    }

    /**
     * Unregisters the remote volume controller which was previously registered with
     * {@link #registerRemoteVolumeController(IRemoteVolumeController)}.
     * Only for use by System UI and Settings application.
     *
     * @param rvc The volume controller which was registered.
     * @hide
     */
    public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
        try {
            mService.unregisterRemoteVolumeController(rvc);
        } catch (RemoteException e) {
            Log.e(TAG, "Error in unregisterRemoteVolumeController.", e);
        }
    }

+2 −1
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ public class MediaSessions {
        mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
        mInit = true;
        postUpdateSessions();
        mMgr.setRemoteVolumeController(mRvc);
        mMgr.registerRemoteVolumeController(mRvc);
    }

    protected void postUpdateSessions() {
@@ -110,6 +110,7 @@ public class MediaSessions {
        if (D.BUG) Log.d(TAG, "destroy");
        mInit = false;
        mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
        mMgr.unregisterRemoteVolumeController(mRvc);
    }

    /**
+54 −34
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -138,9 +139,9 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
    private MediaSessionRecord mGlobalPrioritySession;
    private AudioPlayerStateMonitor mAudioPlayerStateMonitor;

    // Used to notify system UI when remote volume was changed. TODO find a
    // better way to handle this.
    private IRemoteVolumeController mRvc;
    // Used to notify System UI and Settings when remote volume was changed.
    final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers =
            new RemoteCallbackList<>();

    public MediaSessionServiceImpl(Context context) {
        mContext = context;
@@ -281,20 +282,23 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
    }

    /**
     * Tells the system UI that volume has changed on an active remote session.
     * Tells the System UI and Settings app that volume has changed on an active remote session.
     */
    public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
        synchronized (mLock) {
            if (mRvc == null || !session.isActive()) {
        if (!session.isActive()) {
            return;
        }
        int size = mRemoteVolumeControllers.beginBroadcast();
        MediaSession.Token token = session.getSessionToken();
        for (int i = size - 1; i >= 0; i--) {
            try {
                mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
                cb.remoteVolumeChanged(token, flags);
            } catch (Exception e) {
                Log.w(TAG, "Error sending volume change to system UI.", e);
                mRvc = null;
                Log.w(TAG, "Error sending volume change.", e);
            }
        }
        mRemoteVolumeControllers.finishBroadcast();
    }

    @Override
@@ -497,7 +501,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
     */
    private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
            int resolvedUserId) {
        if (isCurrentVolumeController(pid, uid)) return;
        if (hasStatusBarServicePermission(pid, uid)) return;
        if (mContext
                .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
                != PackageManager.PERMISSION_GRANTED
@@ -507,14 +511,14 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
        }
    }

    private boolean isCurrentVolumeController(int pid, int uid) {
    private boolean hasStatusBarServicePermission(int pid, int uid) {
        return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                pid, uid) == PackageManager.PERMISSION_GRANTED;
    }

    private void enforceSystemUiPermission(String action, int pid, int uid) {
        if (!isCurrentVolumeController(pid, uid)) {
            throw new SecurityException("Only system ui may " + action);
    private void enforceStatusBarServicePermission(String action, int pid, int uid) {
        if (!hasStatusBarServicePermission(pid, uid)) {
            throw new SecurityException("Only System UI and Settings may " + action);
        }
    }

@@ -638,20 +642,25 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
    }

    private void pushRemoteVolumeUpdateLocked(int userId) {
        if (mRvc != null) {
            try {
        FullUserRecord user = getFullUserRecordLocked(userId);
        if (user == null) {
            Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
            return;
        }

        int size = mRemoteVolumeControllers.beginBroadcast();
        MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
                mRvc.updateRemoteController(record == null ? null : record.getSessionToken());
            } catch (RemoteException e) {
                Log.w(TAG, "Error sending default remote volume to sys ui.", e);
                mRvc = null;
        MediaSession.Token token = record == null ? null : record.getSessionToken();

        for (int i = size - 1; i >= 0; i--) {
            try {
                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
                cb.updateRemoteController(token);
            } catch (Exception e) {
                Log.w(TAG, "Error sending default remote volume.", e);
            }
        }
        mRemoteVolumeControllers.finishBroadcast();
    }

    void pushSession2TokensChangedLocked(int userId) {
@@ -1661,15 +1670,26 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
        }

        @Override
        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
        public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
            final int pid = Binder.getCallingPid();
            final int uid = Binder.getCallingUid();
            final long token = Binder.clearCallingIdentity();
            try {
                enforceSystemUiPermission("listen for volume changes", pid, uid);
                synchronized (mLock) {
                    mRvc = rvc;
                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
                mRemoteVolumeControllers.register(rvc);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @Override
        public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
            final int pid = Binder.getCallingPid();
            final int uid = Binder.getCallingUid();
            final long token = Binder.clearCallingIdentity();
            try {
                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
                mRemoteVolumeControllers.unregister(rvc);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
@@ -1755,8 +1775,8 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {

        private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
                int pid, int uid) throws RemoteException {
            // Allow API calls from the System UI
            if (isCurrentVolumeController(pid, uid)) {
            // Allow API calls from the System UI and Settings
            if (hasStatusBarServicePermission(pid, uid)) {
                return true;
            }