Loading packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt +16 −8 Original line number Diff line number Diff line Loading @@ -33,24 +33,32 @@ class MediaDataCombineLatest @Inject constructor( init { dataSource.addListener(object : MediaDataManager.Listener { override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) { if (oldKey != null && !oldKey.equals(key)) { val s = entries[oldKey]?.second entries[key] = data to entries[oldKey]?.second entries.remove(oldKey) if (oldKey != null && oldKey != key && entries.contains(oldKey)) { entries[key] = data to entries.remove(oldKey)?.second update(key, oldKey) } else { entries[key] = data to entries[key]?.second update(key, key) } update(key, oldKey) } override fun onMediaDataRemoved(key: String) { remove(key) } }) 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 update(key, key) } } override fun onKeyRemoved(key: String) { remove(key) } Loading packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +7 −5 Original line number Diff line number Diff line Loading @@ -71,7 +71,8 @@ class MediaDeviceManager @Inject constructor( val controller = data.token?.let { MediaController(context, it) } entry = Token(key, controller, localMediaManagerFactory.create(data.packageName)) entry = Token(key, oldKey, controller, localMediaManagerFactory.create(data.packageName)) entries[key] = entry entry.start() } Loading @@ -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 data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name) listeners.forEach { it.onMediaDeviceChanged(key, data) it.onMediaDeviceChanged(key, oldKey, data) } } interface Listener { /** 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. */ fun onKeyRemoved(key: String) } private inner class Token( val key: String, val oldKey: String?, val controller: MediaController?, val localMediaManager: LocalMediaManager ) : LocalMediaManager.DeviceCallback { Loading @@ -125,7 +127,7 @@ class MediaDeviceManager @Inject constructor( set(value) { if (!started || value != field) { field = value processDevice(key, value) processDevice(key, oldKey, value) } } fun start() { Loading packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java +65 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import android.graphics.Color; Loading @@ -47,6 +48,7 @@ import java.util.Map; public class MediaDataCombineLatestTest extends SysuiTestCase { 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 PACKAGE = "PKG"; private static final int BG_COLOR = Color.RED; Loading Loading @@ -97,7 +99,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void eventNotEmittedWithoutMedia() { // WHEN device source emits an event without media data mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // THEN an event isn't emitted verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any()); } Loading @@ -105,7 +107,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void emitEventAfterDeviceFirst() { // GIVEN that a device event has already been received mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // WHEN media event is received mDataListener.onMediaDataLoaded(KEY, null, mMediaData); // THEN the listener receives a combined event Loading @@ -119,13 +121,71 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { // GIVEN that media event has already been received mDataListener.onMediaDataLoaded(KEY, null, mMediaData); // WHEN device event is received mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // THEN the listener receives a combined event ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture()); 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 public void mediaDataRemoved() { // WHEN media data is removed without first receiving device or data Loading @@ -143,7 +203,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void mediaDataRemovedAfterDeviceEvent() { mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); mDataListener.onMediaDataRemoved(KEY); verify(mListener).onMediaDataRemoved(eq(KEY)); } Loading @@ -152,7 +212,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { public void mediaDataKeyUpdated() { // GIVEN that device and media events have already been received mDataListener.onMediaDataLoaded(KEY, null, mMediaData); mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // WHEN the key is changed mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData); // THEN the listener gets a load event with the correct keys Loading packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +8 −7 Original line number Diff line number Diff line Loading @@ -166,7 +166,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { // THEN the listener for the old key should removed. verify(lmm).unregisterCallback(any()) // AND a new device event emitted val data = captureDeviceData(KEY) val data = captureDeviceData(KEY, KEY_OLD) assertThat(data.enabled).isTrue() assertThat(data.name).isEqualTo(DEVICE_NAME) } Loading @@ -179,13 +179,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() { // 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()) verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any()) } @Test fun unknownOldKey() { manager.onMediaDataLoaded(KEY, "unknown", mediaData) verify(listener).onMediaDeviceChanged(eq(KEY), any()) val oldKey = "unknown" manager.onMediaDataLoaded(KEY, oldKey, mediaData) verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any()) } @Test Loading Loading @@ -223,7 +224,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { manager.removeListener(listener) // THEN it doesn't receive device events manager.onMediaDataLoaded(KEY, null, mediaData) verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any()) } @Test Loading Loading @@ -318,9 +319,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() { return captor.getValue() } fun captureDeviceData(key: String): MediaDeviceData { fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData { 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() } } Loading
packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt +16 −8 Original line number Diff line number Diff line Loading @@ -33,24 +33,32 @@ class MediaDataCombineLatest @Inject constructor( init { dataSource.addListener(object : MediaDataManager.Listener { override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) { if (oldKey != null && !oldKey.equals(key)) { val s = entries[oldKey]?.second entries[key] = data to entries[oldKey]?.second entries.remove(oldKey) if (oldKey != null && oldKey != key && entries.contains(oldKey)) { entries[key] = data to entries.remove(oldKey)?.second update(key, oldKey) } else { entries[key] = data to entries[key]?.second update(key, key) } update(key, oldKey) } override fun onMediaDataRemoved(key: String) { remove(key) } }) 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 update(key, key) } } override fun onKeyRemoved(key: String) { remove(key) } Loading
packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +7 −5 Original line number Diff line number Diff line Loading @@ -71,7 +71,8 @@ class MediaDeviceManager @Inject constructor( val controller = data.token?.let { MediaController(context, it) } entry = Token(key, controller, localMediaManagerFactory.create(data.packageName)) entry = Token(key, oldKey, controller, localMediaManagerFactory.create(data.packageName)) entries[key] = entry entry.start() } Loading @@ -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 data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name) listeners.forEach { it.onMediaDeviceChanged(key, data) it.onMediaDeviceChanged(key, oldKey, data) } } interface Listener { /** 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. */ fun onKeyRemoved(key: String) } private inner class Token( val key: String, val oldKey: String?, val controller: MediaController?, val localMediaManager: LocalMediaManager ) : LocalMediaManager.DeviceCallback { Loading @@ -125,7 +127,7 @@ class MediaDeviceManager @Inject constructor( set(value) { if (!started || value != field) { field = value processDevice(key, value) processDevice(key, oldKey, value) } } fun start() { Loading
packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java +65 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import android.graphics.Color; Loading @@ -47,6 +48,7 @@ import java.util.Map; public class MediaDataCombineLatestTest extends SysuiTestCase { 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 PACKAGE = "PKG"; private static final int BG_COLOR = Color.RED; Loading Loading @@ -97,7 +99,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void eventNotEmittedWithoutMedia() { // WHEN device source emits an event without media data mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // THEN an event isn't emitted verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any()); } Loading @@ -105,7 +107,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void emitEventAfterDeviceFirst() { // GIVEN that a device event has already been received mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // WHEN media event is received mDataListener.onMediaDataLoaded(KEY, null, mMediaData); // THEN the listener receives a combined event Loading @@ -119,13 +121,71 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { // GIVEN that media event has already been received mDataListener.onMediaDataLoaded(KEY, null, mMediaData); // WHEN device event is received mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // THEN the listener receives a combined event ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture()); 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 public void mediaDataRemoved() { // WHEN media data is removed without first receiving device or data Loading @@ -143,7 +203,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void mediaDataRemovedAfterDeviceEvent() { mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); mDataListener.onMediaDataRemoved(KEY); verify(mListener).onMediaDataRemoved(eq(KEY)); } Loading @@ -152,7 +212,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { public void mediaDataKeyUpdated() { // GIVEN that device and media events have already been received mDataListener.onMediaDataLoaded(KEY, null, mMediaData); mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData); mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData); // WHEN the key is changed mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData); // THEN the listener gets a load event with the correct keys Loading
packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +8 −7 Original line number Diff line number Diff line Loading @@ -166,7 +166,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { // THEN the listener for the old key should removed. verify(lmm).unregisterCallback(any()) // AND a new device event emitted val data = captureDeviceData(KEY) val data = captureDeviceData(KEY, KEY_OLD) assertThat(data.enabled).isTrue() assertThat(data.name).isEqualTo(DEVICE_NAME) } Loading @@ -179,13 +179,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() { // 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()) verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any()) } @Test fun unknownOldKey() { manager.onMediaDataLoaded(KEY, "unknown", mediaData) verify(listener).onMediaDeviceChanged(eq(KEY), any()) val oldKey = "unknown" manager.onMediaDataLoaded(KEY, oldKey, mediaData) verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any()) } @Test Loading Loading @@ -223,7 +224,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { manager.removeListener(listener) // THEN it doesn't receive device events manager.onMediaDataLoaded(KEY, null, mediaData) verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any()) } @Test Loading Loading @@ -318,9 +319,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() { return captor.getValue() } fun captureDeviceData(key: String): MediaDeviceData { fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData { 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() } }