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

Commit 370cd05a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Update device name on audio info changed" into rvc-qpr-dev am: a51344f7

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12688130

Change-Id: I992dee95566f53ac34cf4d523de381e095cd7204
parents cf00541f a51344f7
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.media

import android.content.Context
import android.media.MediaRouter2Manager
import android.media.session.MediaController
import androidx.annotation.AnyThread
@@ -24,20 +23,22 @@ import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
import com.android.systemui.Dumpable
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.concurrent.Executor
import javax.inject.Inject

private const val PLAYBACK_TYPE_UNKNOWN = 0

/**
 * Provides information about the route (ie. device) where playback is occurring.
 */
class MediaDeviceManager @Inject constructor(
    private val context: Context,
    private val controllerFactory: MediaControllerFactory,
    private val localMediaManagerFactory: LocalMediaManagerFactory,
    private val mr2manager: MediaRouter2Manager,
    @Main private val fgExecutor: Executor,
@@ -71,7 +72,7 @@ class MediaDeviceManager @Inject constructor(
        if (entry == null || entry?.token != data.token) {
            entry?.stop()
            val controller = data.token?.let {
                MediaController(context, it)
                controllerFactory.create(it)
            }
            entry = Entry(key, oldKey, controller,
                    localMediaManagerFactory.create(data.packageName))
@@ -122,11 +123,12 @@ class MediaDeviceManager @Inject constructor(
        val oldKey: String?,
        val controller: MediaController?,
        val localMediaManager: LocalMediaManager
    ) : LocalMediaManager.DeviceCallback {
    ) : LocalMediaManager.DeviceCallback, MediaController.Callback() {

        val token
            get() = controller?.sessionToken
        private var started = false
        private var playbackType = PLAYBACK_TYPE_UNKNOWN
        private var current: MediaDevice? = null
            set(value) {
                if (!started || value != field) {
@@ -141,6 +143,8 @@ class MediaDeviceManager @Inject constructor(
        fun start() = bgExecutor.execute {
            localMediaManager.registerCallback(this)
            localMediaManager.startScan()
            playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
            controller?.registerCallback(this)
            updateCurrent()
            started = true
        }
@@ -148,20 +152,35 @@ class MediaDeviceManager @Inject constructor(
        @AnyThread
        fun stop() = bgExecutor.execute {
            started = false
            controller?.unregisterCallback(this)
            localMediaManager.stopScan()
            localMediaManager.unregisterCallback(this)
        }

        fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
            val route = controller?.let {
            val routingSession = controller?.let {
                mr2manager.getRoutingSessionForMediaController(it)
            }
            val selectedRoutes = routingSession?.let {
                mr2manager.getSelectedRoutes(it)
            }
            with(pw) {
                println("    current device is ${current?.name}")
                val type = controller?.playbackInfo?.playbackType
                println("    PlaybackType=$type (1 for local, 2 for remote)")
                println("    route=$route")
                println("    PlaybackType=$type (1 for local, 2 for remote) cached=$playbackType")
                println("    routingSession=$routingSession")
                println("    selectedRoutes=$selectedRoutes")
            }
        }

        @WorkerThread
        override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) {
            val newPlaybackType = info?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
            if (newPlaybackType == playbackType) {
                return
            }
            playbackType = newPlaybackType
            updateCurrent()
        }

        override fun onDeviceListUpdate(devices: List<MediaDevice>?) = bgExecutor.execute {
+46 −28
Original line number Diff line number Diff line
@@ -16,13 +16,12 @@

package com.android.systemui.media

import android.app.Notification
import android.graphics.drawable.Drawable
import android.media.MediaMetadata
import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
import android.media.session.MediaController
import android.media.session.MediaController.PlaybackInfo
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -55,7 +54,6 @@ private const val KEY = "TEST_KEY"
private const val KEY_OLD = "TEST_KEY_OLD"
private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
private const val DEVICE_NAME = "DEVICE_NAME"
private const val USER_ID = 0
@@ -68,6 +66,7 @@ private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
public class MediaDeviceManagerTest : SysuiTestCase() {

    private lateinit var manager: MediaDeviceManager
    @Mock private lateinit var controllerFactory: MediaControllerFactory
    @Mock private lateinit var lmmFactory: LocalMediaManagerFactory
    @Mock private lateinit var lmm: LocalMediaManager
    @Mock private lateinit var mr2: MediaRouter2Manager
@@ -78,10 +77,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
    @Mock private lateinit var device: MediaDevice
    @Mock private lateinit var icon: Drawable
    @Mock private lateinit var route: RoutingSessionInfo
    @Mock private lateinit var controller: MediaController
    @Mock private lateinit var playbackInfo: PlaybackInfo
    private lateinit var session: MediaSession
    private lateinit var metadataBuilder: MediaMetadata.Builder
    private lateinit var playbackBuilder: PlaybackState.Builder
    private lateinit var notifBuilder: Notification.Builder
    private lateinit var mediaData: MediaData
    @JvmField @Rule val mockito = MockitoJUnit.rule()

@@ -89,8 +87,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
    fun setUp() {
        fakeFgExecutor = FakeExecutor(FakeSystemClock())
        fakeBgExecutor = FakeExecutor(FakeSystemClock())
        manager = MediaDeviceManager(context, lmmFactory, mr2, fakeFgExecutor, fakeBgExecutor,
                dumpster)
        manager = MediaDeviceManager(controllerFactory, lmmFactory, mr2, fakeFgExecutor,
                fakeBgExecutor, dumpster)
        manager.addListener(listener)

        // Configure mocks.
@@ -101,28 +99,13 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
        whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route)

        // Create a media sesssion and notification for testing.
        metadataBuilder = MediaMetadata.Builder().apply {
            putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
            putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
        }
        playbackBuilder = PlaybackState.Builder().apply {
            setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
            setActions(PlaybackState.ACTION_PLAY)
        }
        session = MediaSession(context, SESSION_KEY).apply {
            setMetadata(metadataBuilder.build())
            setPlaybackState(playbackBuilder.build())
        }
        session.setActive(true)
        notifBuilder = Notification.Builder(context, "NONE").apply {
            setContentTitle(SESSION_TITLE)
            setContentText(SESSION_ARTIST)
            setSmallIcon(android.R.drawable.ic_media_pause)
            setStyle(Notification.MediaStyle().setMediaSession(session.getSessionToken()))
        }
        session = MediaSession(context, SESSION_KEY)

        mediaData = MediaData(USER_ID, true, 0, PACKAGE, null, null, SESSION_TITLE, null,
            emptyList(), emptyList(), PACKAGE, session.sessionToken, clickIntent = null,
            device = null, active = true, resumeAction = null)
        whenever(controllerFactory.create(session.sessionToken))
                .thenReturn(controller)
    }

    @After
@@ -336,6 +319,41 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
        assertThat(data.icon).isNull()
    }

    @Test
    fun audioInfoChanged() {
        whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL)
        whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
        // GIVEN a controller with local playback type
        manager.onMediaDataLoaded(KEY, null, mediaData)
        fakeBgExecutor.runAllReady()
        fakeFgExecutor.runAllReady()
        reset(mr2)
        // WHEN onAudioInfoChanged fires with remote playback type
        whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
        val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java)
        verify(controller).registerCallback(captor.capture())
        captor.value.onAudioInfoChanged(playbackInfo)
        // THEN the route is checked
        verify(mr2).getRoutingSessionForMediaController(eq(controller))
    }

    @Test
    fun audioInfoHasntChanged() {
        whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
        whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
        // GIVEN a controller with remote playback type
        manager.onMediaDataLoaded(KEY, null, mediaData)
        fakeBgExecutor.runAllReady()
        fakeFgExecutor.runAllReady()
        reset(mr2)
        // WHEN onAudioInfoChanged fires with remote playback type
        val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java)
        verify(controller).registerCallback(captor.capture())
        captor.value.onAudioInfoChanged(playbackInfo)
        // THEN the route is not checked
        verify(mr2, never()).getRoutingSessionForMediaController(eq(controller))
    }

    fun captureCallback(): LocalMediaManager.DeviceCallback {
        val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java)
        verify(lmm).registerCallback(captor.capture())