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

Commit 8d98da09 authored by Santiago Seifert's avatar Santiago Seifert Committed by Android (Google) Code Review
Browse files

Merge "Hide MediaSession details from MediaSessions clients" into main

parents 008fb9dd 5e2ebbd7
Loading
Loading
Loading
Loading
+43 −21
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.MediaController.PlaybackInfo
import android.media.session.MediaSession
import android.media.session.MediaSessionManager
import android.media.session.PlaybackState
@@ -98,16 +99,22 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
    }

    /** Set volume `level` to remote media `token` */
    fun setVolume(token: MediaSession.Token, level: Int) {
    fun setVolume(sessionId: SessionId, volumeLevel: Int) {
        when (sessionId) {
            is SessionId.Media -> setMediaSessionVolume(sessionId.token, volumeLevel)
        }
    }

    private fun setMediaSessionVolume(token: MediaSession.Token, volumeLevel: Int) {
        val record = mRecords[token]
        if (record == null) {
            Log.w(TAG, "setVolume: No record found for token $token")
            return
        }
        if (D.BUG) {
            Log.d(TAG, "Setting level to $level")
            Log.d(TAG, "Setting level to $volumeLevel")
        }
        record.controller.setVolumeTo(level, 0)
        record.controller.setVolumeTo(volumeLevel, 0)
    }

    private fun onRemoteVolumeChangedH(sessionToken: MediaSession.Token, flags: Int) {
@@ -122,7 +129,7 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
            )
        }
        val token = controller.sessionToken
        mCallbacks.onRemoteVolumeChanged(token, flags)
        mCallbacks.onRemoteVolumeChanged(SessionId.from(token), flags)
    }

    private fun onUpdateRemoteSessionListH(sessionToken: MediaSession.Token?) {
@@ -158,7 +165,7 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
                controller.registerCallback(record, mHandler)
            }
            val record = mRecords[token]
            val remote = isRemote(playbackInfo)
            val remote = playbackInfo.isRemote()
            if (remote) {
                updateRemoteH(token, record!!.name, playbackInfo)
                record.sentRemote = true
@@ -172,7 +179,7 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
                Log.d(TAG, "Removing " + record.name + " sentRemote=" + record.sentRemote)
            }
            if (record.sentRemote) {
                mCallbacks.onRemoteRemoved(token)
                mCallbacks.onRemoteRemoved(SessionId.from(token))
                record.sentRemote = false
            }
        }
@@ -213,8 +220,8 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
    private fun updateRemoteH(
        token: MediaSession.Token,
        name: String?,
        pi: MediaController.PlaybackInfo,
    ) = mCallbacks.onRemoteUpdate(token, name, pi)
        playbackInfo: PlaybackInfo,
    ) = mCallbacks.onRemoteUpdate(SessionId.from(token), name, VolumeInfo.from(playbackInfo))

    private inner class MediaControllerRecord(val controller: MediaController) :
        MediaController.Callback() {
@@ -225,7 +232,7 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
            return method + " " + controller.packageName + " "
        }

        override fun onAudioInfoChanged(info: MediaController.PlaybackInfo) {
        override fun onAudioInfoChanged(info: PlaybackInfo) {
            if (D.BUG) {
                Log.d(
                    TAG,
@@ -235,9 +242,9 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
                        sentRemote),
                )
            }
            val remote = isRemote(info)
            val remote = info.isRemote()
            if (!remote && sentRemote) {
                mCallbacks.onRemoteRemoved(controller.sessionToken)
                mCallbacks.onRemoteRemoved(SessionId.from(controller.sessionToken))
                sentRemote = false
            } else if (remote) {
                updateRemoteH(controller.sessionToken, name, info)
@@ -301,20 +308,36 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
        }
    }

    /** Opaque id for ongoing sessions that support volume adjustment. */
    sealed interface SessionId {

        companion object {
            fun from(token: MediaSession.Token) = Media(token)
        }

        data class Media(val token: MediaSession.Token) : SessionId
    }

    /** Holds session volume information. */
    data class VolumeInfo(val currentVolume: Int, val maxVolume: Int) {

        companion object {

            fun from(playbackInfo: PlaybackInfo) =
                VolumeInfo(playbackInfo.currentVolume, playbackInfo.maxVolume)
        }
    }

    /** Callback for remote media sessions */
    interface Callbacks {
        /** Invoked when remote media session is updated */
        fun onRemoteUpdate(
            token: MediaSession.Token?,
            name: String?,
            pi: MediaController.PlaybackInfo?,
        )
        fun onRemoteUpdate(token: SessionId?, name: String?, volumeInfo: VolumeInfo?)

        /** Invoked when remote media session is removed */
        fun onRemoteRemoved(token: MediaSession.Token?)
        fun onRemoteRemoved(token: SessionId?)

        /** Invoked when remote volume is changed */
        fun onRemoteVolumeChanged(token: MediaSession.Token?, flags: Int)
        fun onRemoteVolumeChanged(token: SessionId?, flags: Int)
    }

    companion object {
@@ -325,12 +348,11 @@ class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
        const val UPDATE_REMOTE_SESSION_LIST: Int = 3

        private const val USE_SERVICE_LABEL = false

        private fun isRemote(pi: MediaController.PlaybackInfo?): Boolean =
            pi != null && pi.playbackType == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE
    }
}

private fun PlaybackInfo?.isRemote() = this?.playbackType == PlaybackInfo.PLAYBACK_TYPE_REMOTE

private fun MediaController.dump(n: Int, writer: PrintWriter) {
    writer.println("  Controller $n: $packageName")

+5 −2
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.keyguard.TestScopeProvider;
import com.android.settingslib.volume.MediaSessions;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCaseExtKt;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -268,13 +269,15 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
    @Test
    public void testOnRemoteVolumeChanged_newStream_noNullPointer() {
        MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
        mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(token, 0);
        var sessionId = MediaSessions.SessionId.Companion.from(token);
        mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(sessionId, 0);
    }

    @Test
    public void testOnRemoteRemove_newStream_noNullPointer() {
        MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
        mVolumeController.mMediaSessionsCallbacksW.onRemoteRemoved(token);
        var sessionId = MediaSessions.SessionId.Companion.from(token);
        mVolumeController.mMediaSessionsCallbacksW.onRemoteRemoved(sessionId);
    }

    @Test
+17 −16
Original line number Diff line number Diff line
@@ -37,8 +37,6 @@ import android.media.IAudioService;
import android.media.IVolumeController;
import android.media.MediaRouter2Manager;
import android.media.VolumePolicy;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession.Token;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -61,6 +59,7 @@ import androidx.lifecycle.Observer;

import com.android.internal.annotations.GuardedBy;
import com.android.settingslib.volume.MediaSessions;
import com.android.settingslib.volume.MediaSessions.SessionId;
import com.android.systemui.Dumpable;
import com.android.systemui.Flags;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -1402,12 +1401,13 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
    }

    protected final class MediaSessionsCallbacks implements MediaSessions.Callbacks {
        private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
        private final HashMap<SessionId, Integer> mRemoteStreams = new HashMap<>();

        private int mNextStream = DYNAMIC_STREAM_REMOTE_START_INDEX;

        @Override
        public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
        public void onRemoteUpdate(
                    SessionId token, String name, MediaSessions.VolumeInfo volumeInfo) {
                addStream(token, "onRemoteUpdate");

                int stream = 0;
@@ -1415,14 +1415,15 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
                    stream = mRemoteStreams.get(token);
                }
                Slog.d(TAG,
                        "onRemoteUpdate: stream: " + stream + " volume: " + pi.getCurrentVolume());
                        "onRemoteUpdate: stream: "
                                + stream + " volume: " + volumeInfo.getCurrentVolume());
                boolean changed = mState.states.indexOfKey(stream) < 0;
                final StreamState ss = streamStateW(stream);
                ss.dynamic = true;
                ss.levelMin = 0;
                ss.levelMax = pi.getMaxVolume();
                if (ss.level != pi.getCurrentVolume()) {
                    ss.level = pi.getCurrentVolume();
                ss.levelMax = volumeInfo.getMaxVolume();
                if (ss.level != volumeInfo.getCurrentVolume()) {
                    ss.level = volumeInfo.getCurrentVolume();
                    changed = true;
                }
                if (!Objects.equals(ss.remoteLabel, name)) {
@@ -1437,11 +1438,11 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
        }

        @Override
        public void onRemoteVolumeChanged(Token token, int flags) {
                addStream(token, "onRemoteVolumeChanged");
        public void onRemoteVolumeChanged(SessionId sessionId, int flags) {
                addStream(sessionId, "onRemoteVolumeChanged");
                int stream = 0;
                synchronized (mRemoteStreams) {
                    stream = mRemoteStreams.get(token);
                    stream = mRemoteStreams.get(sessionId);
                }
                final boolean showUI = shouldShowUI(flags);
                Slog.d(TAG, "onRemoteVolumeChanged: stream: " + stream + " showui? " + showUI);
@@ -1459,7 +1460,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
        }

        @Override
        public void onRemoteRemoved(Token token) {
        public void onRemoteRemoved(SessionId token) {
            int stream;
            synchronized (mRemoteStreams) {
                if (!mRemoteStreams.containsKey(token)) {
@@ -1480,7 +1481,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
        }

        public void setStreamVolume(int stream, int level) {
            final Token token = findToken(stream);
            final SessionId token = findToken(stream);
            if (token == null) {
                Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
                return;
@@ -1488,9 +1489,9 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
            mMediaSessions.setVolume(token, level);
        }

        private Token findToken(int stream) {
        private SessionId findToken(int stream) {
            synchronized (mRemoteStreams) {
                for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
                for (Map.Entry<SessionId, Integer> entry : mRemoteStreams.entrySet()) {
                    if (entry.getValue().equals(stream)) {
                        return entry.getKey();
                    }
@@ -1499,7 +1500,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
            return null;
        }

        private void addStream(Token token, String triggeringMethod) {
        private void addStream(SessionId token, String triggeringMethod) {
            synchronized (mRemoteStreams) {
                if (!mRemoteStreams.containsKey(token)) {
                    mRemoteStreams.put(token, mNextStream);