Merge "Forward device updates when info changes" into tm-dev am: a2b34c4c21

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

Change-Id: I6d43d20198da900da0db332abf1473129a340229
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Beth Thibodeau
2022-06-16 00:45:08 +00:00
committed by Automerger Merge Worker
3 changed files with 105 additions and 3 deletions

View File

@@ -216,4 +216,20 @@ data class MediaDeviceData
/** Unique id for this device */
val id: String? = null
)
) {
/**
* Check whether [MediaDeviceData] objects are equal in all fields except the icon. The icon
* is ignored because it can change by reference frequently depending on the device type's
* implementation, but this is not usually relevant unless other info has changed
*/
fun equalsWithoutIcon(other: MediaDeviceData?): Boolean {
if (other == null) {
return false
}
return enabled == other.enabled &&
name == other.name &&
intent == other.intent &&
id == other.id
}
}

View File

@@ -155,8 +155,8 @@ class MediaDeviceManager @Inject constructor(
private var playbackType = PLAYBACK_TYPE_UNKNOWN
private var current: MediaDeviceData? = null
set(value) {
val hasSameId = value?.id != null && value.id == field?.id
if (!started || (!hasSameId && value != field)) {
val sameWithoutIcon = value != null && value.equalsWithoutIcon(field)
if (!started || !sameWithoutIcon) {
field = value
fgExecutor.execute {
processDevice(key, oldKey, value)

View File

@@ -47,7 +47,9 @@ import org.mockito.Mockito.any
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@@ -55,6 +57,7 @@ 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 DEVICE_ID = "DEVICE_ID"
private const val DEVICE_NAME = "DEVICE_NAME"
private const val REMOTE_DEVICE_NAME = "REMOTE_DEVICE_NAME"
@@ -456,6 +459,89 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
verify(mr2, never()).getRoutingSessionForMediaController(eq(controller))
}
@Test
fun deviceIdChanged_informListener() {
// GIVEN a notification is added, with a particular device connected
whenever(device.id).thenReturn(DEVICE_ID)
manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// and later the manager gets a new device ID
val deviceCallback = captureCallback()
val updatedId = DEVICE_ID + "_new"
whenever(device.id).thenReturn(updatedId)
deviceCallback.onDeviceListUpdate(mutableListOf(device))
// THEN the listener gets the updated info
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
val dataCaptor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
verify(listener, times(2)).onMediaDeviceChanged(eq(KEY), any(), dataCaptor.capture())
val firstDevice = dataCaptor.allValues.get(0)
assertThat(firstDevice.id).isEqualTo(DEVICE_ID)
val secondDevice = dataCaptor.allValues.get(1)
assertThat(secondDevice.id).isEqualTo(updatedId)
}
@Test
fun deviceNameChanged_informListener() {
// GIVEN a notification is added, with a particular device connected
whenever(device.id).thenReturn(DEVICE_ID)
whenever(device.name).thenReturn(DEVICE_NAME)
manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
// and later the manager gets a new device name
val deviceCallback = captureCallback()
val updatedName = DEVICE_NAME + "_new"
whenever(device.name).thenReturn(updatedName)
deviceCallback.onDeviceListUpdate(mutableListOf(device))
// THEN the listener gets the updated info
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
val dataCaptor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
verify(listener, times(2)).onMediaDeviceChanged(eq(KEY), any(), dataCaptor.capture())
val firstDevice = dataCaptor.allValues.get(0)
assertThat(firstDevice.name).isEqualTo(DEVICE_NAME)
val secondDevice = dataCaptor.allValues.get(1)
assertThat(secondDevice.name).isEqualTo(updatedName)
}
@Test
fun deviceIconChanged_doesNotCallListener() {
// GIVEN a notification is added, with a particular device connected
whenever(device.id).thenReturn(DEVICE_ID)
whenever(device.name).thenReturn(DEVICE_NAME)
val firstIcon = mock(Drawable::class.java)
whenever(device.icon).thenReturn(firstIcon)
manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
val dataCaptor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
verify(listener).onMediaDeviceChanged(eq(KEY), any(), dataCaptor.capture())
// and later the manager gets a callback with only the icon changed
val deviceCallback = captureCallback()
val secondIcon = mock(Drawable::class.java)
whenever(device.icon).thenReturn(secondIcon)
deviceCallback.onDeviceListUpdate(mutableListOf(device))
// THEN the listener is not called again
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
verifyNoMoreInteractions(listener)
}
@Test
fun testRemotePlaybackDeviceOverride() {
whenever(route.name).thenReturn(DEVICE_NAME)