Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47f5fd1f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add flag to allow remote sessions to be resumable" into tm-qpr-dev am: 1877b30c

parents eb6424e7 1877b30c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -373,6 +373,9 @@ object Flags {
    // TODO(b/267166152) : Tracking Bug
    val MEDIA_RETAIN_RECOMMENDATIONS = unreleasedFlag(916, "media_retain_recommendations")

    // TODO(b/270437894): Tracking Bug
    val MEDIA_REMOTE_RESUME = unreleasedFlag(917, "media_remote_resume")

    // 1000 - dock
    val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")

+5 −2
Original line number Diff line number Diff line
@@ -1339,10 +1339,13 @@ class MediaDataManager(
    fun onNotificationRemoved(key: String) {
        Assert.isMainThread()
        val removed = mediaEntries.remove(key) ?: return

        val isEligibleForResume =
            removed.isLocalSession() ||
                (mediaFlags.isRemoteResumeAllowed() &&
                    removed.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
        if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
        } else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
        } else if (useMediaResumption && removed.resumeAction != null && isEligibleForResume) {
            convertToResumePlayer(key, removed)
        } else if (mediaFlags.isRetainingPlayersEnabled()) {
            handlePossibleRemoval(key, removed, notificationRemoved = true)
+8 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.pipeline.RESUME_MEDIA_TIMEOUT
import com.android.systemui.media.controls.util.MediaFlags
import com.android.systemui.settings.UserTracker
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Utils
@@ -63,7 +64,8 @@ constructor(
    private val tunerService: TunerService,
    private val mediaBrowserFactory: ResumeMediaBrowserFactory,
    dumpManager: DumpManager,
    private val systemClock: SystemClock
    private val systemClock: SystemClock,
    private val mediaFlags: MediaFlags,
) : MediaDataManager.Listener, Dumpable {

    private var useMediaResumption: Boolean = Utils.useMediaResumption(context)
@@ -231,7 +233,11 @@ constructor(
                mediaBrowser = null
            }
            // If we don't have a resume action, check if we haven't already
            if (data.resumeAction == null && !data.hasCheckedForResume && data.isLocalSession()) {
            val isEligibleForResume =
                data.isLocalSession() ||
                    (mediaFlags.isRemoteResumeAllowed() &&
                        data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
            if (data.resumeAction == null && !data.hasCheckedForResume && isEligibleForResume) {
                // TODO also check for a media button receiver intended for restarting (b/154127084)
                Log.d(TAG, "Checking for service component for " + data.packageName)
                val pm = context.packageManager
+3 −0
Original line number Diff line number Diff line
@@ -61,4 +61,7 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) {

    /** If true, do not automatically dismiss the recommendation card */
    fun isPersistentSsCardEnabled() = featureFlags.isEnabled(Flags.MEDIA_RETAIN_RECOMMENDATIONS)

    /** Check whether we allow remote media to generate resume controls */
    fun isRemoteResumeAllowed() = featureFlags.isEnabled(Flags.MEDIA_REMOTE_RESUME)
}
+75 −44
Original line number Diff line number Diff line
@@ -139,6 +139,7 @@ class MediaDataManagerTest : SysuiTestCase() {
    @Mock private lateinit var logger: MediaUiEventLogger
    lateinit var mediaDataManager: MediaDataManager
    lateinit var mediaNotification: StatusBarNotification
    lateinit var remoteCastNotification: StatusBarNotification
    @Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
    private val clock = FakeSystemClock()
    @Mock private lateinit var tunerService: TunerService
@@ -207,6 +208,20 @@ class MediaDataManagerTest : SysuiTestCase() {
                }
                build()
            }
        remoteCastNotification =
            SbnBuilder().run {
                setPkg(SYSTEM_PACKAGE_NAME)
                modifyNotification(context).also {
                    it.setSmallIcon(android.R.drawable.ic_media_pause)
                    it.setStyle(
                        MediaStyle().apply {
                            setMediaSession(session.sessionToken)
                            setRemotePlaybackInfo("Remote device", 0, null)
                        }
                    )
                }
                build()
            }
        metadataBuilder =
            MediaMetadata.Builder().apply {
                putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
@@ -247,6 +262,7 @@ class MediaDataManagerTest : SysuiTestCase() {
        whenever(mediaFlags.isExplicitIndicatorEnabled()).thenReturn(true)
        whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false)
        whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
        whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(false)
        whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
        whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(false)
    }
@@ -400,33 +416,8 @@ class MediaDataManagerTest : SysuiTestCase() {

    @Test
    fun testOnNotificationAdded_isRcn_markedRemote() {
        val rcn =
            SbnBuilder().run {
                setPkg(SYSTEM_PACKAGE_NAME)
                modifyNotification(context).also {
                    it.setSmallIcon(android.R.drawable.ic_media_pause)
                    it.setStyle(
                        MediaStyle().apply {
                            setMediaSession(session.sessionToken)
                            setRemotePlaybackInfo("Remote device", 0, null)
                        }
                    )
                }
                build()
            }
        addNotificationAndLoad(remoteCastNotification)

        mediaDataManager.onNotificationAdded(KEY, rcn)
        assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
        assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
        verify(listener)
            .onMediaDataLoaded(
                eq(KEY),
                eq(null),
                capture(mediaDataCaptor),
                eq(true),
                eq(0),
                eq(false)
            )
        assertThat(mediaDataCaptor.value!!.playbackLocation)
            .isEqualTo(MediaData.PLAYBACK_CAST_REMOTE)
        verify(logger)
@@ -709,6 +700,56 @@ class MediaDataManagerTest : SysuiTestCase() {
        verify(listener).onMediaDataRemoved(eq(KEY))
    }

    @Test
    fun testOnNotificationRemoved_withResumption_isRemoteAndRemoteAllowed() {
        // With the flag enabled to allow remote media to resume
        whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(true)

        // GIVEN that the manager has a notification with a resume action, but is not local
        whenever(controller.metadata).thenReturn(metadataBuilder.build())
        whenever(playbackInfo.playbackType)
            .thenReturn(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
        addNotificationAndLoad()
        val data = mediaDataCaptor.value
        val dataRemoteWithResume =
            data.copy(resumeAction = Runnable {}, playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
        mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)

        // WHEN the notification is removed
        mediaDataManager.onNotificationRemoved(KEY)

        // THEN the media data is converted to a resume state
        verify(listener)
            .onMediaDataLoaded(
                eq(PACKAGE_NAME),
                eq(KEY),
                capture(mediaDataCaptor),
                eq(true),
                eq(0),
                eq(false)
            )
        assertThat(mediaDataCaptor.value.resumption).isTrue()
    }

    @Test
    fun testOnNotificationRemoved_withResumption_isRcnAndRemoteAllowed() {
        // With the flag enabled to allow remote media to resume
        whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(true)

        // GIVEN that the manager has a remote cast notification
        addNotificationAndLoad(remoteCastNotification)
        val data = mediaDataCaptor.value
        assertThat(data.playbackLocation).isEqualTo(MediaData.PLAYBACK_CAST_REMOTE)
        val dataRemoteWithResume = data.copy(resumeAction = Runnable {})
        mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)

        // WHEN the RCN is removed
        mediaDataManager.onNotificationRemoved(KEY)

        // THEN the media data is removed
        verify(listener).onMediaDataRemoved(eq(KEY))
    }

    @Test
    fun testOnNotificationRemoved_withResumption_tooManyPlayers() {
        // Given the maximum number of resume controls already
@@ -1654,22 +1695,7 @@ class MediaDataManagerTest : SysuiTestCase() {
            )

        // update to remote cast
        val rcn =
            SbnBuilder().run {
                setPkg(SYSTEM_PACKAGE_NAME) // System package
                modifyNotification(context).also {
                    it.setSmallIcon(android.R.drawable.ic_media_pause)
                    it.setStyle(
                        MediaStyle().apply {
                            setMediaSession(session.sessionToken)
                            setRemotePlaybackInfo("Remote device", 0, null)
                        }
                    )
                }
                build()
            }

        mediaDataManager.onNotificationAdded(KEY, rcn)
        mediaDataManager.onNotificationAdded(KEY, remoteCastNotification)
        assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
        assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
        verify(logger)
@@ -2038,9 +2064,14 @@ class MediaDataManagerTest : SysuiTestCase() {
        verify(listener).onMediaDataRemoved(eq(KEY))
    }

    /** Helper function to add a media notification and capture the resulting MediaData */
    /** Helper function to add a basic media notification and capture the resulting MediaData */
    private fun addNotificationAndLoad() {
        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
        addNotificationAndLoad(mediaNotification)
    }

    /** Helper function to add the given notification and capture the resulting MediaData */
    private fun addNotificationAndLoad(sbn: StatusBarNotification) {
        mediaDataManager.onNotificationAdded(KEY, sbn)
        assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
        assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
        verify(listener)
Loading