Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9a91b39 authored by Robert Snoeberger's avatar Robert Snoeberger
Browse files

Migrate from old key when combining device and media data

Fixes: 160256461
Test: manual - Play Spotify. Dismiss app in overview. Open app in
launcher and select a cast device. Start playing again and check media
player in QS. Verify that a cast icon appears in upper right corner.

Change-Id: I7df9e57853db792ee6589b066dce2bb49f36dffc
parent fa99bb4b
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -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)
            }
+7 −5
Original line number Diff line number Diff line
@@ -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()
        }
@@ -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 {
@@ -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() {
+65 −5
Original line number Diff line number Diff line
@@ -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;
@@ -46,6 +47,7 @@ import java.util.ArrayList;
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;
@@ -96,7 +98,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());
    }
@@ -104,7 +106,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
@@ -118,13 +120,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
@@ -142,7 +202,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));
    }
@@ -151,7 +211,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
+8 −7
Original line number Diff line number Diff line
@@ -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)
    }
@@ -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
@@ -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
@@ -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()
    }
}