Only filter when remote session has associated notification

Bug: 167706409
Test: manual - Cast from Google Play Books and check that media controls
are available in QS.

Change-Id: Ifc404be2de6f5f87a1d43e3b51d3ca00c73c6e06
This commit is contained in:
Robert Snoeberger
2020-09-11 15:24:52 -04:00
parent e14fbaad44
commit 8cc72bdf3a
2 changed files with 52 additions and 5 deletions

View File

@@ -52,9 +52,12 @@ class MediaSessionBasedFilter @Inject constructor(
private val packageControllers: LinkedHashMap<String, MutableList<MediaController>> =
LinkedHashMap()
// Keep track of the key used for the session tokens. This information is used to know when
// Keep track of the key used for the session tokens. This information is used to know when to
// dispatch a removed event so that a media object for a local session will be removed.
private val keyedTokens: MutableMap<String, MutableList<MediaSession.Token>> = mutableMapOf()
private val keyedTokens: MutableMap<String, MutableSet<MediaSession.Token>> = mutableMapOf()
// Keep track of which media session tokens have associated notifications.
private val tokensWithNotifications: MutableSet<MediaSession.Token> = mutableSetOf()
private val sessionListener = object : MediaSessionManager.OnActiveSessionsChangedListener {
override fun onActiveSessionsChanged(controllers: List<MediaController>) {
@@ -90,6 +93,9 @@ class MediaSessionBasedFilter @Inject constructor(
*/
override fun onMediaDataLoaded(key: String, oldKey: String?, info: MediaData) {
backgroundExecutor.execute {
info.token?.let {
tokensWithNotifications.add(it)
}
val isMigration = oldKey != null && key != oldKey
if (isMigration) {
keyedTokens.remove(oldKey)?.let { removed -> keyedTokens.put(key, removed) }
@@ -99,7 +105,7 @@ class MediaSessionBasedFilter @Inject constructor(
tokens ->
tokens.add(info.token)
} ?: run {
val tokens = mutableListOf(info.token)
val tokens = mutableSetOf(info.token)
keyedTokens.put(key, tokens)
}
}
@@ -110,7 +116,8 @@ class MediaSessionBasedFilter @Inject constructor(
}
// Limiting search to only apps with a single remote session.
val remote = if (remoteControllers?.size == 1) remoteControllers.firstOrNull() else null
if (isMigration || remote == null || remote.sessionToken == info.token) {
if (isMigration || remote == null || remote.sessionToken == info.token ||
!tokensWithNotifications.contains(remote.sessionToken)) {
// Not filtering in this case. Passing the event along to listeners.
dispatchMediaDataLoaded(key, oldKey, info)
} else {
@@ -159,5 +166,6 @@ class MediaSessionBasedFilter @Inject constructor(
packageControllers.put(controller.packageName, tokens)
}
}
tokensWithNotifications.retainAll(controllers.map { it.sessionToken })
}
}

View File

@@ -225,7 +225,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
@Test
fun remoteSession_loadedEventNotFiltered() {
// GIVEN a remove session
// GIVEN a remote session
whenever(controller1.getPlaybackInfo()).thenReturn(remotePlaybackInfo)
val controllers = listOf(controller1)
whenever(mediaSessionManager.getActiveSessions(any())).thenReturn(controllers)
@@ -259,6 +259,22 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
verify(mediaListener, never()).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData2))
}
@Test
fun remoteAndLocalSessions_remoteSessionWithoutNotification() {
// GIVEN remote and local sessions
whenever(controller2.getPlaybackInfo()).thenReturn(remotePlaybackInfo)
val controllers = listOf(controller1, controller2)
whenever(mediaSessionManager.getActiveSessions(any())).thenReturn(controllers)
sessionListener.onActiveSessionsChanged(controllers)
// WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(KEY, null, mediaData1)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered because there isn't a notification for the remote
// session.
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1))
}
@Test
fun remoteAndLocalHaveDifferentKeys_localLoadedEventFiltered() {
// GIVEN remote and local sessions
@@ -284,6 +300,29 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
verify(mediaListener).onMediaDataRemoved(eq(key2))
}
@Test
fun remoteAndLocalHaveDifferentKeys_remoteSessionWithoutNotification() {
// GIVEN remote and local sessions
val key1 = "KEY_1"
val key2 = "KEY_2"
whenever(controller2.getPlaybackInfo()).thenReturn(remotePlaybackInfo)
val controllers = listOf(controller1, controller2)
whenever(mediaSessionManager.getActiveSessions(any())).thenReturn(controllers)
sessionListener.onActiveSessionsChanged(controllers)
// WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(key1, null, mediaData1)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1))
// WHEN a loaded event is received that matches the remote session
filter.onMediaDataLoaded(key2, null, mediaData2)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2))
}
@Test
fun multipleRemoteSessions_loadedEventNotFiltered() {
// GIVEN two remote sessions