Merge "Migrate from old key when combining device and media data" into rvc-qpr-dev am: 20ef70906c

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

Change-Id: I3b5e4c05ba07f852e6cf6ff07731d307abad346b
This commit is contained in:
Robert Snoeberger
2020-07-09 15:58:02 +00:00
committed by Automerger Merge Worker
4 changed files with 96 additions and 25 deletions

View File

@@ -33,24 +33,32 @@ class MediaDataCombineLatest @Inject constructor(
init { init {
dataSource.addListener(object : MediaDataManager.Listener { dataSource.addListener(object : MediaDataManager.Listener {
override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) { override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
if (oldKey != null && !oldKey.equals(key)) { if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
val s = entries[oldKey]?.second entries[key] = data to entries.remove(oldKey)?.second
entries[key] = data to entries[oldKey]?.second update(key, oldKey)
entries.remove(oldKey)
} else { } else {
entries[key] = data to entries[key]?.second entries[key] = data to entries[key]?.second
update(key, key)
} }
update(key, oldKey)
} }
override fun onMediaDataRemoved(key: String) { override fun onMediaDataRemoved(key: String) {
remove(key) remove(key)
} }
}) })
deviceSource.addListener(object : MediaDeviceManager.Listener { deviceSource.addListener(object : MediaDeviceManager.Listener {
override fun onMediaDeviceChanged(key: String, data: MediaDeviceData?) { override fun onMediaDeviceChanged(
key: String,
oldKey: String?,
data: MediaDeviceData?
) {
if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
entries[key] = entries.remove(oldKey)?.first to data
update(key, oldKey)
} else {
entries[key] = entries[key]?.first to data entries[key] = entries[key]?.first to data
update(key, key) update(key, key)
} }
}
override fun onKeyRemoved(key: String) { override fun onKeyRemoved(key: String) {
remove(key) remove(key)
} }

View File

@@ -71,7 +71,8 @@ class MediaDeviceManager @Inject constructor(
val controller = data.token?.let { val controller = data.token?.let {
MediaController(context, it) MediaController(context, it)
} }
entry = Token(key, controller, localMediaManagerFactory.create(data.packageName)) entry = Token(key, oldKey, controller,
localMediaManagerFactory.create(data.packageName))
entries[key] = entry entries[key] = entry
entry.start() entry.start()
} }
@@ -98,23 +99,24 @@ class MediaDeviceManager @Inject constructor(
} }
} }
private fun processDevice(key: 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)
listeners.forEach { listeners.forEach {
it.onMediaDeviceChanged(key, data) it.onMediaDeviceChanged(key, oldKey, data)
} }
} }
interface Listener { interface Listener {
/** Called when the route has changed for a given notification. */ /** Called when the route has changed for a given notification. */
fun onMediaDeviceChanged(key: String, data: MediaDeviceData?) fun onMediaDeviceChanged(key: String, oldKey: String?, data: MediaDeviceData?)
/** Called when the notification was removed. */ /** Called when the notification was removed. */
fun onKeyRemoved(key: String) fun onKeyRemoved(key: String)
} }
private inner class Token( private inner class Token(
val key: String, val key: String,
val oldKey: String?,
val controller: MediaController?, val controller: MediaController?,
val localMediaManager: LocalMediaManager val localMediaManager: LocalMediaManager
) : LocalMediaManager.DeviceCallback { ) : LocalMediaManager.DeviceCallback {
@@ -125,7 +127,7 @@ class MediaDeviceManager @Inject constructor(
set(value) { set(value) {
if (!started || value != field) { if (!started || value != field) {
field = value field = value
processDevice(key, value) processDevice(key, oldKey, value)
} }
} }
fun start() { fun start() {

View File

@@ -22,6 +22,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.graphics.Color; import android.graphics.Color;
@@ -47,6 +48,7 @@ import java.util.Map;
public class MediaDataCombineLatestTest extends SysuiTestCase { public class MediaDataCombineLatestTest extends SysuiTestCase {
private static final String KEY = "TEST_KEY"; private static final String KEY = "TEST_KEY";
private static final String OLD_KEY = "TEST_KEY_OLD";
private static final String APP = "APP"; private static final String APP = "APP";
private static final String PACKAGE = "PKG"; private static final String PACKAGE = "PKG";
private static final int BG_COLOR = Color.RED; private static final int BG_COLOR = Color.RED;
@@ -97,7 +99,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test @Test
public void eventNotEmittedWithoutMedia() { public void eventNotEmittedWithoutMedia() {
// WHEN device source emits an event without media data // WHEN device source emits an event without media data
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN an event isn't emitted // THEN an event isn't emitted
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any()); verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any());
} }
@@ -105,7 +107,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test @Test
public void emitEventAfterDeviceFirst() { public void emitEventAfterDeviceFirst() {
// GIVEN that a device event has already been received // GIVEN that a device event has already been received
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN media event is received // WHEN media event is received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData); mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN the listener receives a combined event // THEN the listener receives a combined event
@@ -119,13 +121,71 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// GIVEN that media event has already been received // GIVEN that media event has already been received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData); mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// WHEN device event is received // WHEN device event is received
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN the listener receives a combined event // THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture()); verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull(); assertThat(captor.getValue().getDevice()).isNotNull();
} }
@Test
public void migrateKeyMediaFirst() {
// GIVEN that media and device info has already been received
mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
reset(mListener);
// WHEN a key migration event is received
mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@Test
public void migrateKeyDeviceFirst() {
// GIVEN that media and device info has already been received
mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
reset(mListener);
// WHEN a key migration event is received
mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@Test
public void migrateKeyMediaAfter() {
// GIVEN that media and device info has already been received
mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
reset(mListener);
// WHEN a second key migration event is received for media
mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
// THEN the key has already been migrated
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@Test
public void migrateKeyDeviceAfter() {
// GIVEN that media and device info has already been received
mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
reset(mListener);
// WHEN a second key migration event is received for the device
mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
// THEN the key has already be migrated
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@Test @Test
public void mediaDataRemoved() { public void mediaDataRemoved() {
// WHEN media data is removed without first receiving device or data // WHEN media data is removed without first receiving device or data
@@ -143,7 +203,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test @Test
public void mediaDataRemovedAfterDeviceEvent() { public void mediaDataRemovedAfterDeviceEvent() {
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
mDataListener.onMediaDataRemoved(KEY); mDataListener.onMediaDataRemoved(KEY);
verify(mListener).onMediaDataRemoved(eq(KEY)); verify(mListener).onMediaDataRemoved(eq(KEY));
} }
@@ -152,7 +212,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void mediaDataKeyUpdated() { public void mediaDataKeyUpdated() {
// GIVEN that device and media events have already been received // GIVEN that device and media events have already been received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData); mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN the key is changed // WHEN the key is changed
mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData); mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData);
// THEN the listener gets a load event with the correct keys // THEN the listener gets a load event with the correct keys

View File

@@ -166,7 +166,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// 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
val data = captureDeviceData(KEY) val data = captureDeviceData(KEY, KEY_OLD)
assertThat(data.enabled).isTrue() assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(DEVICE_NAME) assertThat(data.name).isEqualTo(DEVICE_NAME)
} }
@@ -179,13 +179,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// WHEN the new key is the same as the old key // WHEN the new key is the same as the old key
manager.onMediaDataLoaded(KEY, KEY, mediaData) manager.onMediaDataLoaded(KEY, KEY, mediaData)
// THEN no event should be emitted // THEN no event should be emitted
verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any())
} }
@Test @Test
fun unknownOldKey() { fun unknownOldKey() {
manager.onMediaDataLoaded(KEY, "unknown", mediaData) val oldKey = "unknown"
verify(listener).onMediaDeviceChanged(eq(KEY), any()) manager.onMediaDataLoaded(KEY, oldKey, mediaData)
verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any())
} }
@Test @Test
@@ -223,7 +224,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
manager.removeListener(listener) manager.removeListener(listener)
// THEN it doesn't receive device events // THEN it doesn't receive device events
manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataLoaded(KEY, null, mediaData)
verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any())
} }
@Test @Test
@@ -318,9 +319,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
return captor.getValue() return captor.getValue()
} }
fun captureDeviceData(key: String): MediaDeviceData { fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData {
val captor = ArgumentCaptor.forClass(MediaDeviceData::class.java) val captor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
verify(listener).onMediaDeviceChanged(eq(key), captor.capture()) verify(listener).onMediaDeviceChanged(eq(key), eq(oldKey), captor.capture())
return captor.getValue() return captor.getValue()
} }
} }