summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt54
7 files changed, 80 insertions, 50 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index e5a9ac10389f..f150381f4070 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -42,7 +42,7 @@ class MediaCarouselController @Inject constructor(
private val mediaHostStatesManager: MediaHostStatesManager,
private val activityStarter: ActivityStarter,
@Main executor: DelayableExecutor,
- mediaManager: MediaDataManager,
+ private val mediaManager: MediaDataManager,
configurationController: ConfigurationController,
falsingManager: FalsingManager
) {
@@ -109,6 +109,7 @@ class MediaCarouselController @Inject constructor(
private val pageIndicator: PageIndicator
private val visualStabilityCallback: VisualStabilityManager.Callback
private var needsReordering: Boolean = false
+ private var keysNeedRemoval = mutableSetOf<String>()
private var isRtl: Boolean = false
set(value) {
if (value != field) {
@@ -161,6 +162,10 @@ class MediaCarouselController @Inject constructor(
needsReordering = false
reorderAllPlayers()
}
+
+ keysNeedRemoval.forEach { removePlayer(it) }
+ keysNeedRemoval.clear()
+
// Let's reset our scroll position
mediaCarouselScrollHandler.scrollToStart()
}
@@ -168,13 +173,19 @@ class MediaCarouselController @Inject constructor(
true /* persistent */)
mediaManager.addListener(object : MediaDataManager.Listener {
override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
- if (!data.active && !Utils.useMediaResumption(context)) {
- // This view is inactive, let's remove this! This happens e.g when dismissing /
- // timing out a view. We still have the data around because resumption could
- // be on, but we should save the resources and release this.
- onMediaDataRemoved(key)
+ addOrUpdatePlayer(key, oldKey, data)
+ val canRemove = data.isPlaying?.let { !it } ?: data.isClearable
+ if (canRemove && !Utils.useMediaResumption(context)) {
+ // This view isn't playing, let's remove this! This happens e.g when
+ // dismissing/timing out a view. We still have the data around because
+ // resumption could be on, but we should save the resources and release this.
+ if (visualStabilityManager.isReorderingAllowed) {
+ onMediaDataRemoved(key)
+ } else {
+ keysNeedRemoval.add(key)
+ }
} else {
- addOrUpdatePlayer(key, oldKey, data)
+ keysNeedRemoval.remove(key)
}
}
@@ -236,12 +247,12 @@ class MediaCarouselController @Inject constructor(
var newPlayer = mediaControlPanelFactory.get()
newPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
- MediaPlayerData.addMediaPlayer(key, data, newPlayer)
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
newPlayer.view?.player?.setLayoutParams(lp)
newPlayer.bind(data)
newPlayer.setListening(currentlyExpanded)
+ MediaPlayerData.addMediaPlayer(key, data, newPlayer)
updatePlayerToState(newPlayer, noAnimation = true)
reorderAllPlayers()
} else {
@@ -271,6 +282,9 @@ class MediaCarouselController @Inject constructor(
removed.onDestroy()
mediaCarouselScrollHandler.onPlayersChanged()
updatePageIndicator()
+
+ // Inform the media manager of a potentially late dismissal
+ mediaManager.dismissMediaData(key, 0L)
}
}
@@ -478,12 +492,11 @@ class MediaCarouselController @Inject constructor(
internal object MediaPlayerData {
private data class MediaSortKey(
val data: MediaData,
- val updateTime: Long = 0,
- val isPlaying: Boolean = false
+ val updateTime: Long = 0
)
private val comparator =
- compareByDescending<MediaSortKey> { it.isPlaying }
+ compareByDescending<MediaSortKey> { it.data.isPlaying }
.thenByDescending { it.data.isLocalSession }
.thenByDescending { !it.data.resumption }
.thenByDescending { it.updateTime }
@@ -493,7 +506,7 @@ internal object MediaPlayerData {
fun addMediaPlayer(key: String, data: MediaData, player: MediaControlPanel) {
removeMediaPlayer(key)
- val sortKey = MediaSortKey(data, System.currentTimeMillis(), player.isPlaying())
+ val sortKey = MediaSortKey(data, System.currentTimeMillis())
mediaData.put(key, sortKey)
mediaPlayers.put(sortKey, player)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index d6a02687c905..40a879abde34 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -94,7 +94,17 @@ data class MediaData(
* Notification key for cancelling a media player after a timeout (when not using resumption.)
*/
val notificationKey: String? = null,
- var hasCheckedForResume: Boolean = false
+ var hasCheckedForResume: Boolean = false,
+
+ /**
+ * If apps do not report PlaybackState, set as null to imply 'undetermined'
+ */
+ val isPlaying: Boolean? = null,
+
+ /**
+ * Set from the notification and used as fallback when PlaybackState cannot be determined
+ */
+ val isClearable: Boolean = true
)
/** State of a media action. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index 0664a41f841d..1f580a953d09 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -136,14 +136,8 @@ class MediaDataFilter @Inject constructor(
/**
* Are there any media entries we should display?
- * If resumption is enabled, this will include inactive players
- * If resumption is disabled, we only want to show active players
*/
- fun hasAnyMedia() = if (mediaResumeListener.isResumptionEnabled()) {
- userEntries.isNotEmpty()
- } else {
- hasActiveMedia()
- }
+ fun hasAnyMedia() = userEntries.isNotEmpty()
/**
* Add a listener for filtered [MediaData] changes
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index b2ad19b5f42f..cb6b22c2321f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -47,6 +47,7 @@ import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
@@ -350,6 +351,16 @@ class MediaDataManager(
}
fun dismissMediaData(key: String, delay: Long) {
+ backgroundExecutor.execute {
+ mediaEntries[key]?.let { mediaData ->
+ if (mediaData.isLocalSession) {
+ mediaData.token?.let {
+ val mediaController = mediaControllerFactory.create(it)
+ mediaController.transportControls.stop()
+ }
+ }
+ }
+ }
foregroundExecutor.executeDelayed({ removeEntry(key) }, delay)
}
@@ -500,6 +511,7 @@ class MediaDataManager(
val isLocalSession = mediaController.playbackInfo?.playbackType ==
MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL ?: true
+ val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
foregroundExecutor.execute {
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
@@ -509,7 +521,8 @@ class MediaDataManager(
smallIconDrawable, artist, song, artWorkIcon, actionIcons,
actionsToShowCollapsed, sbn.packageName, token, notif.contentIntent, null,
active, resumeAction = resumeAction, isLocalSession = isLocalSession,
- notificationKey = key, hasCheckedForResume = hasCheckedForResume))
+ notificationKey = key, hasCheckedForResume = hasCheckedForResume,
+ isPlaying = isPlaying, isClearable = sbn.isClearable()))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index c00b5e92f93d..5b59214afdc9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -125,8 +125,6 @@ class MediaResumeListener @Inject constructor(
}, Settings.Secure.MEDIA_CONTROLS_RESUME_BLOCKED)
}
- fun isResumptionEnabled() = useMediaResumption
-
private fun loadSavedComponents() {
// Make sure list is empty (if we switched users)
resumeComponents.clear()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 89538ac8bc9f..609b8474d134 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -74,7 +74,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
mMediaData = new MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null,
new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, true,
- false, KEY, false);
+ false, KEY, false, false, false);
mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
index da1ec9869d87..ef8d322ca2ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
@@ -25,7 +25,6 @@ import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
-import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -34,6 +33,8 @@ public class MediaPlayerDataTest : SysuiTestCase() {
companion object {
val LOCAL = true
val RESUMPTION = true
+ val PLAYING = true
+ val UNDETERMINED = null
}
@Before
@@ -44,15 +45,13 @@ public class MediaPlayerDataTest : SysuiTestCase() {
@Test
fun addPlayingThenRemote() {
val playerIsPlaying = mock(MediaControlPanel::class.java)
- whenever(playerIsPlaying.isPlaying).thenReturn(true)
- val dataIsPlaying = createMediaData("app1", LOCAL, !RESUMPTION)
+ val dataIsPlaying = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
val playerIsRemote = mock(MediaControlPanel::class.java)
- whenever(playerIsRemote.isPlaying).thenReturn(false)
- val dataIsRemote = createMediaData("app2", !LOCAL, !RESUMPTION)
+ val dataIsRemote = createMediaData("app2", PLAYING, !LOCAL, !RESUMPTION)
- MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying)
MediaPlayerData.addMediaPlayer("2", dataIsRemote, playerIsRemote)
+ MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying)
val players = MediaPlayerData.players()
assertThat(players).hasSize(2)
@@ -63,18 +62,16 @@ public class MediaPlayerDataTest : SysuiTestCase() {
@Ignore("Flaky")
fun switchPlayersPlaying() {
val playerIsPlaying1 = mock(MediaControlPanel::class.java)
- whenever(playerIsPlaying1.isPlaying).thenReturn(true)
- val dataIsPlaying1 = createMediaData("app1", LOCAL, !RESUMPTION)
+ var dataIsPlaying1 = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
val playerIsPlaying2 = mock(MediaControlPanel::class.java)
- whenever(playerIsPlaying2.isPlaying).thenReturn(false)
- val dataIsPlaying2 = createMediaData("app2", LOCAL, !RESUMPTION)
+ var dataIsPlaying2 = createMediaData("app2", !PLAYING, LOCAL, !RESUMPTION)
MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1)
MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2)
- whenever(playerIsPlaying1.isPlaying).thenReturn(false)
- whenever(playerIsPlaying2.isPlaying).thenReturn(true)
+ dataIsPlaying1 = createMediaData("app1", !PLAYING, LOCAL, !RESUMPTION)
+ dataIsPlaying2 = createMediaData("app2", PLAYING, LOCAL, !RESUMPTION)
MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1)
MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2)
@@ -87,38 +84,43 @@ public class MediaPlayerDataTest : SysuiTestCase() {
@Test
fun fullOrderTest() {
val playerIsPlaying = mock(MediaControlPanel::class.java)
- whenever(playerIsPlaying.isPlaying).thenReturn(true)
- val dataIsPlaying = createMediaData("app1", LOCAL, !RESUMPTION)
+ val dataIsPlaying = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
val playerIsPlayingAndRemote = mock(MediaControlPanel::class.java)
- whenever(playerIsPlayingAndRemote.isPlaying).thenReturn(true)
- val dataIsPlayingAndRemote = createMediaData("app2", !LOCAL, !RESUMPTION)
+ val dataIsPlayingAndRemote = createMediaData("app2", PLAYING, !LOCAL, !RESUMPTION)
val playerIsStoppedAndLocal = mock(MediaControlPanel::class.java)
- whenever(playerIsStoppedAndLocal.isPlaying).thenReturn(false)
- val dataIsStoppedAndLocal = createMediaData("app3", LOCAL, !RESUMPTION)
+ val dataIsStoppedAndLocal = createMediaData("app3", !PLAYING, LOCAL, !RESUMPTION)
val playerIsStoppedAndRemote = mock(MediaControlPanel::class.java)
- whenever(playerIsStoppedAndLocal.isPlaying).thenReturn(false)
- val dataIsStoppedAndRemote = createMediaData("app4", !LOCAL, !RESUMPTION)
+ val dataIsStoppedAndRemote = createMediaData("app4", !PLAYING, !LOCAL, !RESUMPTION)
val playerCanResume = mock(MediaControlPanel::class.java)
- whenever(playerCanResume.isPlaying).thenReturn(false)
- val dataCanResume = createMediaData("app5", LOCAL, RESUMPTION)
+ val dataCanResume = createMediaData("app5", !PLAYING, LOCAL, RESUMPTION)
+
+ val playerUndetermined = mock(MediaControlPanel::class.java)
+ val dataUndetermined = createMediaData("app6", UNDETERMINED, LOCAL, RESUMPTION)
MediaPlayerData.addMediaPlayer("3", dataIsStoppedAndLocal, playerIsStoppedAndLocal)
MediaPlayerData.addMediaPlayer("5", dataIsStoppedAndRemote, playerIsStoppedAndRemote)
MediaPlayerData.addMediaPlayer("4", dataCanResume, playerCanResume)
MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying)
MediaPlayerData.addMediaPlayer("2", dataIsPlayingAndRemote, playerIsPlayingAndRemote)
+ MediaPlayerData.addMediaPlayer("6", dataUndetermined, playerUndetermined)
val players = MediaPlayerData.players()
- assertThat(players).hasSize(5)
+ assertThat(players).hasSize(6)
assertThat(players).containsExactly(playerIsPlaying, playerIsPlayingAndRemote,
- playerIsStoppedAndLocal, playerCanResume, playerIsStoppedAndRemote).inOrder()
+ playerIsStoppedAndLocal, playerCanResume, playerIsStoppedAndRemote,
+ playerUndetermined).inOrder()
}
- private fun createMediaData(app: String, isLocalSession: Boolean, resumption: Boolean) =
+ private fun createMediaData(
+ app: String,
+ isPlaying: Boolean?,
+ isLocalSession: Boolean,
+ resumption: Boolean
+ ) =
MediaData(0, false, 0, app, null, null, null, null, emptyList(), emptyList<Int>(), "",
- null, null, null, true, null, isLocalSession, resumption, null, false)
+ null, null, null, true, null, isLocalSession, resumption, null, false, isPlaying)
}