Merge "Move call to MediaRouter2Manager to worker thread" into rvc-qpr-dev

This commit is contained in:
TreeHugger Robot
2020-09-16 14:44:45 +00:00
committed by Android (Google) Code Review
2 changed files with 62 additions and 20 deletions

View File

@@ -19,8 +19,12 @@ package com.android.systemui.media
import android.content.Context import android.content.Context
import android.media.MediaRouter2Manager import android.media.MediaRouter2Manager
import android.media.session.MediaController import android.media.session.MediaController
import androidx.annotation.AnyThread
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import com.android.settingslib.media.LocalMediaManager import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice import com.android.settingslib.media.MediaDevice
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.Dumpable import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
@@ -39,11 +43,12 @@ class MediaDeviceManager @Inject constructor(
private val localMediaManagerFactory: LocalMediaManagerFactory, private val localMediaManagerFactory: LocalMediaManagerFactory,
private val mr2manager: MediaRouter2Manager, private val mr2manager: MediaRouter2Manager,
@Main private val fgExecutor: Executor, @Main private val fgExecutor: Executor,
@Background private val bgExecutor: Executor,
private val mediaDataManager: MediaDataManager, private val mediaDataManager: MediaDataManager,
private val dumpManager: DumpManager private val dumpManager: DumpManager
) : MediaDataManager.Listener, Dumpable { ) : MediaDataManager.Listener, Dumpable {
private val listeners: MutableSet<Listener> = mutableSetOf() private val listeners: MutableSet<Listener> = mutableSetOf()
private val entries: MutableMap<String, Token> = mutableMapOf() private val entries: MutableMap<String, Entry> = mutableMapOf()
init { init {
mediaDataManager.addListener(this) mediaDataManager.addListener(this)
@@ -71,7 +76,7 @@ class MediaDeviceManager @Inject constructor(
val controller = data.token?.let { val controller = data.token?.let {
MediaController(context, it) MediaController(context, it)
} }
entry = Token(key, oldKey, controller, entry = Entry(key, oldKey, controller,
localMediaManagerFactory.create(data.packageName)) localMediaManagerFactory.create(data.packageName))
entries[key] = entry entries[key] = entry
entry.start() entry.start()
@@ -99,6 +104,7 @@ class MediaDeviceManager @Inject constructor(
} }
} }
@MainThread
private fun processDevice(key: String, oldKey: String?, device: MediaDevice?) { private fun processDevice(key: String, oldKey: String?, device: MediaDevice?) {
val enabled = device != null val enabled = device != null
val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name) val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name)
@@ -114,12 +120,13 @@ class MediaDeviceManager @Inject constructor(
fun onKeyRemoved(key: String) fun onKeyRemoved(key: String)
} }
private inner class Token( private inner class Entry(
val key: String, val key: String,
val oldKey: String?, val oldKey: String?,
val controller: MediaController?, val controller: MediaController?,
val localMediaManager: LocalMediaManager val localMediaManager: LocalMediaManager
) : LocalMediaManager.DeviceCallback { ) : LocalMediaManager.DeviceCallback {
val token val token
get() = controller?.sessionToken get() = controller?.sessionToken
private var started = false private var started = false
@@ -127,20 +134,27 @@ class MediaDeviceManager @Inject constructor(
set(value) { set(value) {
if (!started || value != field) { if (!started || value != field) {
field = value field = value
processDevice(key, oldKey, value) fgExecutor.execute {
processDevice(key, oldKey, value)
}
} }
} }
fun start() {
@AnyThread
fun start() = bgExecutor.execute {
localMediaManager.registerCallback(this) localMediaManager.registerCallback(this)
localMediaManager.startScan() localMediaManager.startScan()
updateCurrent() updateCurrent()
started = true started = true
} }
fun stop() {
@AnyThread
fun stop() = bgExecutor.execute {
started = false started = false
localMediaManager.stopScan() localMediaManager.stopScan()
localMediaManager.unregisterCallback(this) localMediaManager.unregisterCallback(this)
} }
fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) { fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
val route = controller?.let { val route = controller?.let {
mr2manager.getRoutingSessionForMediaController(it) mr2manager.getRoutingSessionForMediaController(it)
@@ -152,14 +166,18 @@ class MediaDeviceManager @Inject constructor(
println(" route=$route") println(" route=$route")
} }
} }
override fun onDeviceListUpdate(devices: List<MediaDevice>?) = fgExecutor.execute {
override fun onDeviceListUpdate(devices: List<MediaDevice>?) = bgExecutor.execute {
updateCurrent() updateCurrent()
} }
override fun onSelectedDeviceStateChanged(device: MediaDevice, state: Int) { override fun onSelectedDeviceStateChanged(device: MediaDevice, state: Int) {
fgExecutor.execute { bgExecutor.execute {
updateCurrent() updateCurrent()
} }
} }
@WorkerThread
private fun updateCurrent() { private fun updateCurrent() {
val device = localMediaManager.getCurrentConnectedDevice() val device = localMediaManager.getCurrentConnectedDevice()
controller?.let { controller?.let {

View File

@@ -72,7 +72,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Mock private lateinit var lmmFactory: LocalMediaManagerFactory @Mock private lateinit var lmmFactory: LocalMediaManagerFactory
@Mock private lateinit var lmm: LocalMediaManager @Mock private lateinit var lmm: LocalMediaManager
@Mock private lateinit var mr2: MediaRouter2Manager @Mock private lateinit var mr2: MediaRouter2Manager
private lateinit var fakeExecutor: FakeExecutor private lateinit var fakeFgExecutor: FakeExecutor
private lateinit var fakeBgExecutor: FakeExecutor
@Mock private lateinit var dumpster: DumpManager @Mock private lateinit var dumpster: DumpManager
@Mock private lateinit var listener: MediaDeviceManager.Listener @Mock private lateinit var listener: MediaDeviceManager.Listener
@Mock private lateinit var device: MediaDevice @Mock private lateinit var device: MediaDevice
@@ -87,9 +88,10 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock()) fakeFgExecutor = FakeExecutor(FakeSystemClock())
manager = MediaDeviceManager(context, lmmFactory, mr2, fakeExecutor, mediaDataManager, fakeBgExecutor = FakeExecutor(FakeSystemClock())
dumpster) manager = MediaDeviceManager(context, lmmFactory, mr2, fakeFgExecutor, fakeBgExecutor,
mediaDataManager, dumpster)
manager.addListener(listener) manager.addListener(listener)
// Configure mocks. // Configure mocks.
@@ -144,13 +146,15 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun loadAndRemoveMediaData() { fun loadAndRemoveMediaData() {
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
manager.onMediaDataRemoved(KEY) manager.onMediaDataRemoved(KEY)
fakeBgExecutor.runAllReady()
verify(lmm).unregisterCallback(any()) verify(lmm).unregisterCallback(any())
} }
@Test @Test
fun loadMediaDataWithNullToken() { fun loadMediaDataWithNullToken() {
manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null))
fakeExecutor.runAllReady() fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue() assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(DEVICE_NAME) assertThat(data.name).isEqualTo(DEVICE_NAME)
@@ -163,6 +167,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
reset(listener) reset(listener)
// WHEN data is loaded with a new key // WHEN data is loaded with a new key
manager.onMediaDataLoaded(KEY, KEY_OLD, mediaData) manager.onMediaDataLoaded(KEY, KEY_OLD, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// THEN the listener for the old key should removed. // THEN the listener for the old key should removed.
verify(lmm).unregisterCallback(any()) verify(lmm).unregisterCallback(any())
// AND a new device event emitted // AND a new device event emitted
@@ -186,6 +192,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun unknownOldKey() { fun unknownOldKey() {
val oldKey = "unknown" val oldKey = "unknown"
manager.onMediaDataLoaded(KEY, oldKey, mediaData) manager.onMediaDataLoaded(KEY, oldKey, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any()) verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any())
} }
@@ -193,13 +201,16 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun updateToSessionTokenWithNullRoute() { fun updateToSessionTokenWithNullRoute() {
// GIVEN that media data has been loaded with a null token // GIVEN that media data has been loaded with a null token
manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null))
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
reset(listener)
// WHEN media data is loaded with a different token // WHEN media data is loaded with a different token
// AND that token results in a null route // AND that token results in a null route
reset(listener)
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// THEN the device should be disabled // THEN the device should be disabled
fakeExecutor.runAllReady()
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse() assertThat(data.enabled).isFalse()
assertThat(data.name).isNull() assertThat(data.name).isNull()
@@ -210,7 +221,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun deviceEventOnAddNotification() { fun deviceEventOnAddNotification() {
// WHEN a notification is added // WHEN a notification is added
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
val deviceCallback = captureCallback() fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// THEN the update is dispatched to the listener // THEN the update is dispatched to the listener
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue() assertThat(data.enabled).isTrue()
@@ -230,10 +242,12 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test @Test
fun deviceListUpdate() { fun deviceListUpdate() {
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
val deviceCallback = captureCallback() val deviceCallback = captureCallback()
// WHEN the device list changes // WHEN the device list changes
deviceCallback.onDeviceListUpdate(mutableListOf(device)) deviceCallback.onDeviceListUpdate(mutableListOf(device))
assertThat(fakeExecutor.runAllReady()).isEqualTo(1) assertThat(fakeBgExecutor.runAllReady()).isEqualTo(1)
assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
// THEN the update is dispatched to the listener // THEN the update is dispatched to the listener
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue() assertThat(data.enabled).isTrue()
@@ -244,10 +258,12 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test @Test
fun selectedDeviceStateChanged() { fun selectedDeviceStateChanged() {
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
val deviceCallback = captureCallback() val deviceCallback = captureCallback()
// WHEN the selected device changes state // WHEN the selected device changes state
deviceCallback.onSelectedDeviceStateChanged(device, 1) deviceCallback.onSelectedDeviceStateChanged(device, 1)
assertThat(fakeExecutor.runAllReady()).isEqualTo(1) assertThat(fakeBgExecutor.runAllReady()).isEqualTo(1)
assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
// THEN the update is dispatched to the listener // THEN the update is dispatched to the listener
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue() assertThat(data.enabled).isTrue()
@@ -270,6 +286,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
// WHEN a notification is added // WHEN a notification is added
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// THEN the device is disabled // THEN the device is disabled
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse() assertThat(data.enabled).isFalse()
@@ -281,13 +299,16 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceChanged() { fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceChanged() {
// GIVEN a notif is added // GIVEN a notif is added
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
reset(listener) reset(listener)
// AND MR2Manager returns null for routing session // AND MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
// WHEN the selected device changes state // WHEN the selected device changes state
val deviceCallback = captureCallback() val deviceCallback = captureCallback()
deviceCallback.onSelectedDeviceStateChanged(device, 1) deviceCallback.onSelectedDeviceStateChanged(device, 1)
fakeExecutor.runAllReady() fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// THEN the device is disabled // THEN the device is disabled
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse() assertThat(data.enabled).isFalse()
@@ -299,13 +320,16 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceListUpdate() { fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceListUpdate() {
// GIVEN a notif is added // GIVEN a notif is added
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
reset(listener) reset(listener)
// GIVEN that MR2Manager returns null for routing session // GIVEN that MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
// WHEN the selected device changes state // WHEN the selected device changes state
val deviceCallback = captureCallback() val deviceCallback = captureCallback()
deviceCallback.onDeviceListUpdate(mutableListOf(device)) deviceCallback.onDeviceListUpdate(mutableListOf(device))
fakeExecutor.runAllReady() fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// THEN the device is disabled // THEN the device is disabled
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse() assertThat(data.enabled).isFalse()