diff options
| author | 2020-07-08 00:51:15 +0000 | |
|---|---|---|
| committer | 2020-07-08 00:51:15 +0000 | |
| commit | af41f0ac481c08e8a40d10abdac3c5d4974325d8 (patch) | |
| tree | b287fc3527f984d46e424893ee75a234b0e0eb0a | |
| parent | 4185609ba93ffaa35968c6b8c67a28c7e152444e (diff) | |
| parent | 997a3c73a7c59d6169bcd34c336dbeaf8d8c2051 (diff) | |
Merge "Deduplicate resumption controls when notif removed" into rvc-dev am: 997a3c73a7
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12089063
Change-Id: I5cdf3c8784db9f5a84a40dc67ba41a4b2d734191
3 files changed, 73 insertions, 15 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 127c5dd54d72..e12b7dd259a5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -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) { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 8cb93bfc6d4d..299ae5b50aa9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -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() - listenersCopy.forEach { - it.onMediaDataLoaded(data.packageName, key, updated) + if (migrate) { + listenersCopy.forEach { + 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 { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index 6761b282b26a..59c2d0e86c56 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -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 } } } |