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

Commit 997a3c73 authored by Selim Cinek's avatar Selim Cinek Committed by Android (Google) Code Review
Browse files

Merge "Deduplicate resumption controls when notif removed" into rvc-dev

parents a7111656 5b13c310
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log
import android.util.MathUtils
import android.view.LayoutInflater
import android.view.View
@@ -25,6 +26,7 @@ import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton

private const val TAG = "MediaCarouselController"
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)

/**
@@ -236,7 +238,9 @@ class MediaCarouselController @Inject constructor(
        val oldData = mediaPlayers[oldKey]
        if (oldData != null) {
            val oldData = mediaPlayers.remove(oldKey)
            mediaPlayers.put(key, oldData!!)
            mediaPlayers.put(key, oldData!!)?.let {
                Log.wtf(TAG, "new key $key already exists when migrating from $oldKey")
            }
        }
        var existingPlayer = mediaPlayers[key]
        if (existingPlayer == null) {
@@ -271,6 +275,11 @@ class MediaCarouselController @Inject constructor(
        updatePageIndicator()
        mediaCarouselScrollHandler.onPlayersChanged()
        mediaCarousel.requiresRemeasuring = true
        // Check postcondition: mediaContent should have the same number of children as there are
        // elements in mediaPlayers.
        if (mediaPlayers.size != mediaContent.childCount) {
            Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
        }
    }

    private fun removePlayer(key: String) {
+24 −10
Original line number Diff line number Diff line
@@ -517,22 +517,36 @@ class MediaDataManager(

    fun onNotificationRemoved(key: String) {
        Assert.isMainThread()
        if (useMediaResumption && mediaEntries.get(key)?.resumeAction != null) {
        val removed = mediaEntries.remove(key)
        if (useMediaResumption && removed?.resumeAction != null) {
            Log.d(TAG, "Not removing $key because resumable")
            // Move to resume key aka package name
            val data = mediaEntries.remove(key)!!
            val resumeAction = getResumeMediaAction(data.resumeAction!!)
            val updated = data.copy(token = null, actions = listOf(resumeAction),
            // Move to resume key (aka package name) if that key doesn't already exist.
            val resumeAction = getResumeMediaAction(removed.resumeAction!!)
            val updated = removed.copy(token = null, actions = listOf(resumeAction),
                    actionsToShowInCompact = listOf(0), active = false, resumption = true)
            mediaEntries.put(data.packageName, updated)
            // Notify listeners of "new" controls
            val pkg = removed?.packageName
            val migrate = mediaEntries.put(pkg, updated) == null
            // Notify listeners of "new" controls when migrating or removed and update when not
            val listenersCopy = listeners.toSet()
            if (migrate) {
                listenersCopy.forEach {
                it.onMediaDataLoaded(data.packageName, key, updated)
                    it.onMediaDataLoaded(pkg, key, updated)
                }
            } else {
                // Since packageName is used for the key of the resumption controls, it is
                // possible that another notification has already been reused for the resumption
                // controls of this package. In this case, rather than renaming this player as
                // packageName, just remove it and then send a update to the existing resumption
                // controls.
                listenersCopy.forEach {
                    it.onMediaDataRemoved(key)
                }
                listenersCopy.forEach {
                    it.onMediaDataLoaded(pkg, pkg, updated)
                }
            }
            return
        }
        val removed = mediaEntries.remove(key)
        if (removed != null) {
            val listenersCopy = listeners.toSet()
            listenersCopy.forEach {
+39 −4
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever

private const val KEY = "KEY"
private const val KEY_2 = "KEY_2"
private const val PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "SystemUI"
private const val SESSION_ARTIST = "artist"
@@ -156,8 +157,43 @@ class MediaDataManagerTest : SysuiTestCase() {
        mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
        // WHEN the notification is removed
        mediaDataManager.onNotificationRemoved(KEY)
        // THEN the media data indicates that it is
        // THEN the media data indicates that it is for resumption
        assertThat(listener.data!!.resumption).isTrue()
        // AND the new key is the package name
        assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
        assertThat(listener.oldKey!!).isEqualTo(KEY)
        assertThat(listener.removedKey).isNull()
    }

    @Test
    fun testOnNotificationRemoved_twoWithResumption() {
        // GIVEN that the manager has two notifications with resume actions
        val listener = TestListener()
        mediaDataManager.addListener(listener)
        whenever(controller.metadata).thenReturn(metadataBuilder.build())
        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
        mediaDataManager.onNotificationAdded(KEY_2, mediaNotification)
        assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
        assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
        val data = listener.data!!
        assertThat(data.resumption).isFalse()
        val resumableData = data.copy(resumeAction = Runnable {})
        mediaDataManager.onMediaDataLoaded(KEY, null, resumableData)
        mediaDataManager.onMediaDataLoaded(KEY_2, null, resumableData)
        // WHEN the first is removed
        mediaDataManager.onNotificationRemoved(KEY)
        // THEN the data is for resumption and the key is migrated to the package name
        assertThat(listener.data!!.resumption).isTrue()
        assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
        assertThat(listener.oldKey!!).isEqualTo(KEY)
        assertThat(listener.removedKey).isNull()
        // WHEN the second is removed
        mediaDataManager.onNotificationRemoved(KEY_2)
        // THEN the data is for resumption and the second key is removed
        assertThat(listener.data!!.resumption).isTrue()
        assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
        assertThat(listener.oldKey!!).isEqualTo(PACKAGE_NAME)
        assertThat(listener.removedKey!!).isEqualTo(KEY_2)
    }

    @Test
@@ -190,6 +226,7 @@ class MediaDataManagerTest : SysuiTestCase() {
        var data: MediaData? = null
        var key: String? = null
        var oldKey: String? = null
        var removedKey: String? = null

        override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
            this.key = key
@@ -198,9 +235,7 @@ class MediaDataManagerTest : SysuiTestCase() {
        }

        override fun onMediaDataRemoved(key: String) {
            this.key = key
            oldKey = null
            data = null
            removedKey = key
        }
    }
}