Loading packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +17 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) { Loading packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt +47 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -641,6 +642,46 @@ class MediaDataManagerTest : SysuiTestCase() { verify(listener).onMediaDataRemoved(eq(KEY)) } @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 Loading Loading @@ -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, Loading @@ -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), Loading Loading
packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +17 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) { Loading
packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt +47 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -641,6 +642,46 @@ class MediaDataManagerTest : SysuiTestCase() { verify(listener).onMediaDataRemoved(eq(KEY)) } @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 Loading Loading @@ -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, Loading @@ -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), Loading