diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt index 2f521ea392429..de0af16bc2faf 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt @@ -34,7 +34,6 @@ class MediaDeviceManager @Inject constructor( private val context: Context, private val localMediaManagerFactory: LocalMediaManagerFactory, private val mr2manager: MediaRouter2Manager, - private val featureFlag: MediaFeatureFlag, @Main private val fgExecutor: Executor, private val mediaDataManager: MediaDataManager ) : MediaDataManager.Listener { @@ -56,20 +55,19 @@ class MediaDeviceManager @Inject constructor( fun removeListener(listener: Listener) = listeners.remove(listener) override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) { - if (featureFlag.enabled) { - if (oldKey != null && oldKey != key) { - val oldToken = entries.remove(oldKey) - oldToken?.stop() + if (oldKey != null && oldKey != key) { + val oldEntry = entries.remove(oldKey) + oldEntry?.stop() + } + var entry = entries[key] + if (entry == null || entry?.token != data.token) { + entry?.stop() + val controller = data.token?.let { + MediaController(context, it) } - var tok = entries[key] - if (tok == null && data.token != null) { - val controller = MediaController(context, data.token!!) - tok = Token(key, controller, localMediaManagerFactory.create(data.packageName)) - entries[key] = tok - tok.start() - } - } else { - onMediaDataRemoved(key) + entry = Token(key, controller, localMediaManagerFactory.create(data.packageName)) + entries[key] = entry + entry.start() } } @@ -100,9 +98,11 @@ class MediaDeviceManager @Inject constructor( private inner class Token( val key: String, - val controller: MediaController, + val controller: MediaController?, val localMediaManager: LocalMediaManager ) : LocalMediaManager.DeviceCallback { + val token + get() = controller?.sessionToken private var started = false private var current: MediaDevice? = null set(value) { @@ -132,10 +132,14 @@ class MediaDeviceManager @Inject constructor( } private fun updateCurrent() { val device = localMediaManager.getCurrentConnectedDevice() - val route = mr2manager.getRoutingSessionForMediaController(controller) - // If we get a null route, then don't trust the device. Just set to null to disable the - // output switcher chip. - current = if (route != null) device else null + controller?.let { + val route = mr2manager.getRoutingSessionForMediaController(it) + // If we get a null route, then don't trust the device. Just set to null to disable the + // output switcher chip. + current = if (route != null) device else null + } ?: run { + current = device + } } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt index 3a3140f2ff53e..6fcf6e37572be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt @@ -51,6 +51,7 @@ import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit 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" @@ -69,7 +70,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Mock private lateinit var lmmFactory: LocalMediaManagerFactory @Mock private lateinit var lmm: LocalMediaManager @Mock private lateinit var mr2: MediaRouter2Manager - @Mock private lateinit var featureFlag: MediaFeatureFlag private lateinit var fakeExecutor: FakeExecutor @Mock private lateinit var listener: MediaDeviceManager.Listener @Mock private lateinit var device: MediaDevice @@ -85,8 +85,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Before fun setUp() { fakeExecutor = FakeExecutor(FakeSystemClock()) - manager = MediaDeviceManager(context, lmmFactory, mr2, featureFlag, fakeExecutor, - mediaDataManager) + manager = MediaDeviceManager(context, lmmFactory, mr2, fakeExecutor, mediaDataManager) manager.addListener(listener) // Configure mocks. @@ -95,7 +94,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() { whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm) whenever(lmm.getCurrentConnectedDevice()).thenReturn(device) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route) - whenever(featureFlag.enabled).thenReturn(true) // Create a media sesssion and notification for testing. metadataBuilder = MediaMetadata.Builder().apply { @@ -132,25 +130,76 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun addNotification() { + fun loadMediaData() { manager.onMediaDataLoaded(KEY, null, mediaData) verify(lmmFactory).create(PACKAGE) } @Test - fun featureDisabled() { - whenever(featureFlag.enabled).thenReturn(false) - manager.onMediaDataLoaded(KEY, null, mediaData) - verify(lmmFactory, never()).create(PACKAGE) - } - - @Test - fun addAndRemoveNotification() { + fun loadAndRemoveMediaData() { manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataRemoved(KEY) verify(lmm).unregisterCallback(any()) } + @Test + fun loadMediaDataWithNullToken() { + manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) + fakeExecutor.runAllReady() + val data = captureDeviceData(KEY) + assertThat(data.enabled).isTrue() + assertThat(data.name).isEqualTo(DEVICE_NAME) + } + + @Test + fun loadWithNewKey() { + // GIVEN that media data has been loaded with an old key + manager.onMediaDataLoaded(KEY_OLD, null, mediaData) + reset(listener) + // WHEN data is loaded with a new key + manager.onMediaDataLoaded(KEY, KEY_OLD, mediaData) + // THEN the listener for the old key should removed. + verify(lmm).unregisterCallback(any()) + // AND a new device event emitted + val data = captureDeviceData(KEY) + assertThat(data.enabled).isTrue() + assertThat(data.name).isEqualTo(DEVICE_NAME) + } + + @Test + fun newKeySameAsOldKey() { + // GIVEN that media data has been loaded + manager.onMediaDataLoaded(KEY, null, mediaData) + reset(listener) + // WHEN the new key is the same as the old key + manager.onMediaDataLoaded(KEY, KEY, mediaData) + // THEN no event should be emitted + verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) + } + + @Test + fun unknownOldKey() { + manager.onMediaDataLoaded(KEY, "unknown", mediaData) + verify(listener).onMediaDeviceChanged(eq(KEY), any()) + } + + @Test + fun updateToSessionTokenWithNullRoute() { + // GIVEN that media data has been loaded with a null token + manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) + // WHEN media data is loaded with a different token + // AND that token results in a null route + reset(listener) + whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) + manager.onMediaDataLoaded(KEY, null, mediaData) + // THEN the device should be disabled + fakeExecutor.runAllReady() + val data = captureDeviceData(KEY) + assertThat(data.enabled).isFalse() + assertThat(data.name).isNull() + assertThat(data.icon).isNull() + } + @Test fun deviceEventOnAddNotification() { // WHEN a notification is added @@ -163,6 +212,15 @@ public class MediaDeviceManagerTest : SysuiTestCase() { assertThat(data.icon).isEqualTo(icon) } + @Test + fun removeListener() { + // WHEN a listener is removed + manager.removeListener(listener) + // THEN it doesn't receive device events + manager.onMediaDataLoaded(KEY, null, mediaData) + verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) + } + @Test fun deviceListUpdate() { manager.onMediaDataLoaded(KEY, null, mediaData)