diff options
3 files changed, 65 insertions, 4 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt index 0a948034ca78..db777772d559 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt @@ -67,6 +67,7 @@ import com.android.systemui.media.controls.models.recommendation.EXTRA_VALUE_TRI import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaDataProvider import com.android.systemui.media.controls.resume.MediaResumeListener +import com.android.systemui.media.controls.resume.ResumeMediaBrowser import com.android.systemui.media.controls.util.MediaControllerFactory import com.android.systemui.media.controls.util.MediaDataUtils import com.android.systemui.media.controls.util.MediaFlags @@ -1431,6 +1432,22 @@ class MediaDataManager( notifyMediaDataLoaded(key = pkg, oldKey = pkg, info = updated) } logger.logActiveConvertedToResume(updated.appUid, pkg, updated.instanceId) + + // Limit total number of resume controls + val resumeEntries = mediaEntries.filter { (key, data) -> data.resumption } + val numResume = resumeEntries.size + if (numResume > ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) { + resumeEntries + .toList() + .sortedBy { (key, data) -> data.lastActive } + .subList(0, numResume - ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) + .forEach { (key, data) -> + Log.d(TAG, "Removing excess control $key") + mediaEntries.remove(key) + notifyMediaDataRemoved(key) + logger.logMediaRemoved(data.appUid, data.packageName, data.instanceId) + } + } } fun setMediaResumptionEnabled(isEnabled: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt index aa46b14d11c1..878962dc60b4 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt @@ -40,7 +40,7 @@ val PAUSED_MEDIA_TIMEOUT = @VisibleForTesting val RESUME_MEDIA_TIMEOUT = - SystemProperties.getLong("debug.sysui.media_timeout_resume", TimeUnit.DAYS.toMillis(3)) + SystemProperties.getLong("debug.sysui.media_timeout_resume", TimeUnit.DAYS.toMillis(2)) /** Controller responsible for keeping track of playback states and expiring inactive streams. */ @SysUISingleton diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt index 44e2fbd8465f..5c7d2421cd83 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt @@ -51,6 +51,7 @@ import com.android.systemui.media.controls.models.recommendation.EXTRA_VALUE_TRI import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaDataProvider import com.android.systemui.media.controls.resume.MediaResumeListener +import com.android.systemui.media.controls.resume.ResumeMediaBrowser import com.android.systemui.media.controls.util.MediaControllerFactory import com.android.systemui.media.controls.util.MediaFlags import com.android.systemui.media.controls.util.MediaUiEventLogger @@ -642,6 +643,46 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test + fun testOnNotificationRemoved_withResumption_tooManyPlayers() { + // Given the maximum number of resume controls already + val desc = + MediaDescription.Builder().run { + setTitle(SESSION_TITLE) + build() + } + for (i in 0..ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) { + addResumeControlAndLoad(desc, "$i:$PACKAGE_NAME") + clock.advanceTime(1000) + } + + // And an active, resumable notification + whenever(controller.metadata).thenReturn(metadataBuilder.build()) + addNotificationAndLoad() + val data = mediaDataCaptor.value + assertThat(data.resumption).isFalse() + mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) + + // When the notification is removed + mediaDataManager.onNotificationRemoved(KEY) + + // Then it is converted to resumption + verify(listener) + .onMediaDataLoaded( + eq(PACKAGE_NAME), + eq(KEY), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + assertThat(mediaDataCaptor.value.resumption).isTrue() + assertThat(mediaDataCaptor.value.isPlaying).isFalse() + + // And the oldest resume control was removed + verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME")) + } + + @Test fun testAddResumptionControls() { // WHEN resumption controls are added val desc = @@ -1846,7 +1887,10 @@ class MediaDataManagerTest : SysuiTestCase() { } /** Helper function to add a resumption control and capture the resulting MediaData */ - private fun addResumeControlAndLoad(desc: MediaDescription) { + private fun addResumeControlAndLoad( + desc: MediaDescription, + packageName: String = PACKAGE_NAME + ) { mediaDataManager.addResumptionControls( USER_ID, desc, @@ -1854,14 +1898,14 @@ class MediaDataManagerTest : SysuiTestCase() { session.sessionToken, APP_NAME, pendingIntent, - PACKAGE_NAME + packageName ) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) verify(listener) .onMediaDataLoaded( - eq(PACKAGE_NAME), + eq(packageName), eq(null), capture(mediaDataCaptor), eq(true), |