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

Commit acd0432a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Clean up MEDIA_RETAIN_SESSIONS flag" into main

parents 09c50aab e38f87a8
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -197,9 +197,6 @@ object Flags {
    // TODO(b/254512673): Tracking Bug
    @JvmField val DREAM_MEDIA_TAP_TO_OPEN = unreleasedFlag("dream_media_tap_to_open")

    // TODO(b/266157412): Tracking Bug
    val MEDIA_RETAIN_SESSIONS = unreleasedFlag("media_retain_sessions")

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

+4 −14
Original line number Diff line number Diff line
@@ -1171,8 +1171,6 @@ class LegacyMediaDataManagerImpl(
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
        } else if (isAbleToResume(removed)) {
            convertToResumePlayer(key, removed)
        } else if (mediaFlags.isRetainingPlayersEnabled()) {
            handlePossibleRemoval(key, removed, notificationRemoved = true)
        } else {
            notifyMediaDataRemoved(key)
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
@@ -1198,18 +1196,14 @@ class LegacyMediaDataManagerImpl(
     * if it was removed before becoming inactive. (Assumes that [removed] was removed from
     * [mediaEntries] before this function was called)
     */
    private fun handlePossibleRemoval(
        key: String,
        removed: MediaData,
        notificationRemoved: Boolean = false,
    ) {
    private fun handlePossibleRemoval(key: String, removed: MediaData) {
        val hasSession = removed.token != null
        if (hasSession && removed.semanticActions != null) {
            // The app was using session actions, and the session is still valid: keep player
            if (DEBUG) Log.d(TAG, "Notification removed but using session actions $key")
            mediaEntries.put(key, removed)
            notifyMediaDataLoaded(key, key, removed)
        } else if (!notificationRemoved && removed.semanticActions == null) {
        } else if (removed.semanticActions == null) {
            // The app was using notification actions, and notif wasn't removed yet: keep player
            if (DEBUG) Log.d(TAG, "Session destroyed but using notification actions $key")
            mediaEntries.put(key, removed)
@@ -1220,14 +1214,10 @@ class LegacyMediaDataManagerImpl(
            if (DEBUG) Log.d(TAG, "Removing still-active player $key")
            notifyMediaDataRemoved(key)
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
        } else if (mediaFlags.isRetainingPlayersEnabled() || isAbleToResume(removed)) {
        } else if (isAbleToResume(removed)) {
            // Convert to resume
            if (DEBUG) {
                Log.d(
                    TAG,
                    "Notification ($notificationRemoved) and/or session " +
                        "($hasSession) gone for inactive player $key",
                )
                Log.d(TAG, "Session ($hasSession) gone for inactive player $key")
            }
            convertToResumePlayer(key, removed)
        } else {
+4 −14
Original line number Diff line number Diff line
@@ -1126,8 +1126,6 @@ class MediaDataProcessor(
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
        } else if (isAbleToResume(removed)) {
            convertToResumePlayer(key, removed)
        } else if (mediaFlags.isRetainingPlayersEnabled()) {
            handlePossibleRemoval(key, removed, notificationRemoved = true)
        } else {
            notifyMediaDataRemoved(key)
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
@@ -1153,18 +1151,14 @@ class MediaDataProcessor(
     * if it was removed before becoming inactive. (Assumes that [removed] was removed from
     * [mediaDataRepository.mediaEntries] state before this function was called)
     */
    private fun handlePossibleRemoval(
        key: String,
        removed: MediaData,
        notificationRemoved: Boolean = false,
    ) {
    private fun handlePossibleRemoval(key: String, removed: MediaData) {
        val hasSession = removed.token != null
        if (hasSession && removed.semanticActions != null) {
            // The app was using session actions, and the session is still valid: keep player
            if (DEBUG) Log.d(TAG, "Notification removed but using session actions $key")
            mediaDataRepository.addMediaEntry(key, removed)
            notifyMediaDataLoaded(key, key, removed)
        } else if (!notificationRemoved && removed.semanticActions == null) {
        } else if (removed.semanticActions == null) {
            // The app was using notification actions, and notif wasn't removed yet: keep player
            if (DEBUG) Log.d(TAG, "Session destroyed but using notification actions $key")
            mediaDataRepository.addMediaEntry(key, removed)
@@ -1175,14 +1169,10 @@ class MediaDataProcessor(
            if (DEBUG) Log.d(TAG, "Removing still-active player $key")
            notifyMediaDataRemoved(key)
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
        } else if (mediaFlags.isRetainingPlayersEnabled() || isAbleToResume(removed)) {
        } else if (isAbleToResume(removed)) {
            // Convert to resume
            if (DEBUG) {
                Log.d(
                    TAG,
                    "Notification ($notificationRemoved) and/or session " +
                        "($hasSession) gone for inactive player $key",
                )
                Log.d(TAG, "Session ($hasSession) gone for inactive player $key")
            }
            convertToResumePlayer(key, removed)
        } else {
+0 −7
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.os.UserHandle
import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags as FlagsClassic
import javax.inject.Inject

@SysUISingleton
@@ -39,10 +38,4 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlagsClass
        val featureFlag = Flags.mediaControlsButtonMedia3()
        return featureFlag && compatFlag
    }

    /**
     * If true, keep active media controls for the lifetime of the MediaSession, regardless of
     * whether the underlying notification was dismissed
     */
    fun isRetainingPlayersEnabled() = featureFlags.isEnabled(FlagsClassic.MEDIA_RETAIN_SESSIONS)
}
+0 −221
Original line number Diff line number Diff line
@@ -46,8 +46,6 @@ import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.Flags.MEDIA_RETAIN_SESSIONS
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.controls.domain.resume.MediaResumeListener
@@ -156,7 +154,6 @@ class LegacyMediaDataManagerImplTest(flags: FlagsParameterization) : SysuiTestCa
    private val kosmos = testKosmos().apply { mediaLogger = mockMediaLogger }
    private val testDispatcher = kosmos.testDispatcher
    private val testScope = kosmos.testScope
    private val fakeFeatureFlags = kosmos.fakeFeatureFlagsClassic
    private val mediaControllerFactory = kosmos.fakeMediaControllerFactory
    private val instanceIdSequence = InstanceIdSequenceFake(1 shl 20)

@@ -246,7 +243,6 @@ class LegacyMediaDataManagerImplTest(flags: FlagsParameterization) : SysuiTestCa
        // treat mediaSessionBasedFilter as a listener for testing.
        listener = mediaSessionBasedFilter

        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, false)
        whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
        whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(false)
    }
@@ -1657,210 +1653,6 @@ class LegacyMediaDataManagerImplTest(flags: FlagsParameterization) : SysuiTestCa
        assertThat(mediaDataCaptor.value.isClearable).isFalse()
    }

    @DisableFlags(Flags.FLAG_MEDIA_CONTROLS_BUTTON_MEDIA3)
    @Test
    fun testRetain_notifPlayer_notifRemoved_setToResume() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)

        // When a media control based on notification is added, times out, and then removed
        addNotificationAndLoad()
        mediaDataManager.setInactive(KEY, timedOut = true)
        assertThat(mediaDataCaptor.value.active).isFalse()
        mediaDataManager.onNotificationRemoved(KEY)

        // It is converted to a resume player
        verify(listener)
            .onMediaDataLoaded(
                eq(PACKAGE_NAME),
                eq(KEY),
                capture(mediaDataCaptor),
                eq(true),
                eq(0),
                eq(false),
            )
        assertThat(mediaDataCaptor.value.resumption).isTrue()
        assertThat(mediaDataCaptor.value.active).isFalse()
        verify(logger)
            .logActiveConvertedToResume(
                anyInt(),
                eq(PACKAGE_NAME),
                eq(mediaDataCaptor.value.instanceId),
            )
    }

    @DisableFlags(Flags.FLAG_MEDIA_CONTROLS_BUTTON_MEDIA3)
    @Test
    fun testRetain_notifPlayer_sessionDestroyed_doesNotChange() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)

        // When a media control based on notification is added and times out
        addNotificationAndLoad()
        mediaDataManager.setInactive(KEY, timedOut = true)
        assertThat(mediaDataCaptor.value.active).isFalse()

        // and then the session is destroyed
        sessionCallbackCaptor.value.invoke(KEY)

        // It remains as a regular player
        verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean())
        verify(listener, never())
            .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
    }

    @DisableFlags(Flags.FLAG_MEDIA_CONTROLS_BUTTON_MEDIA3)
    @Test
    fun testRetain_notifPlayer_removeWhileActive_fullyRemoved() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)

        // When a media control based on notification is added and then removed, without timing out
        addNotificationAndLoad()
        val data = mediaDataCaptor.value
        assertThat(data.active).isTrue()
        mediaDataManager.onNotificationRemoved(KEY)

        // It is fully removed
        verify(listener).onMediaDataRemoved(eq(KEY), eq(false))
        verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
        verify(listener, never())
            .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
    }

    @Test
    fun testRetain_canResume_removeWhileActive_setToResume() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)

        // When a media control that supports resumption is added
        addNotificationAndLoad()
        val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
        mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)

        // And then removed while still active
        mediaDataManager.onNotificationRemoved(KEY)

        // It is converted to a resume player
        verify(listener)
            .onMediaDataLoaded(
                eq(PACKAGE_NAME),
                eq(KEY),
                capture(mediaDataCaptor),
                eq(true),
                eq(0),
                eq(false),
            )
        assertThat(mediaDataCaptor.value.resumption).isTrue()
        assertThat(mediaDataCaptor.value.active).isFalse()
        verify(logger)
            .logActiveConvertedToResume(
                anyInt(),
                eq(PACKAGE_NAME),
                eq(mediaDataCaptor.value.instanceId),
            )
    }

    @Test
    fun testRetain_sessionPlayer_notifRemoved_doesNotChange() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)
        addPlaybackStateAction()

        // When a media control with PlaybackState actions is added, times out,
        // and then the notification is removed
        addNotificationAndLoad()
        val data = mediaDataCaptor.value
        assertThat(data.active).isTrue()
        mediaDataManager.setInactive(KEY, timedOut = true)
        mediaDataManager.onNotificationRemoved(KEY)

        // It remains as a regular player
        verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean())
        verify(listener, never())
            .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
    }

    @Test
    fun testRetain_sessionPlayer_sessionDestroyed_setToResume() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)
        addPlaybackStateAction()

        // When a media control with PlaybackState actions is added, times out,
        // and then the session is destroyed
        addNotificationAndLoad()
        val data = mediaDataCaptor.value
        assertThat(data.active).isTrue()
        mediaDataManager.setInactive(KEY, timedOut = true)
        sessionCallbackCaptor.value.invoke(KEY)

        // It is converted to a resume player
        verify(listener)
            .onMediaDataLoaded(
                eq(PACKAGE_NAME),
                eq(KEY),
                capture(mediaDataCaptor),
                eq(true),
                eq(0),
                eq(false),
            )
        assertThat(mediaDataCaptor.value.resumption).isTrue()
        assertThat(mediaDataCaptor.value.active).isFalse()
        verify(logger)
            .logActiveConvertedToResume(
                anyInt(),
                eq(PACKAGE_NAME),
                eq(mediaDataCaptor.value.instanceId),
            )
    }

    @Test
    fun testRetain_sessionPlayer_destroyedWhileActive_noResume_fullyRemoved() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)
        addPlaybackStateAction()

        // When a media control using session actions is added, and then the session is destroyed
        // without timing out first
        addNotificationAndLoad()
        val data = mediaDataCaptor.value
        assertThat(data.active).isTrue()
        sessionCallbackCaptor.value.invoke(KEY)

        // It is fully removed
        verify(listener).onMediaDataRemoved(eq(KEY), eq(false))
        verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
        verify(listener, never())
            .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
    }

    @Test
    fun testRetain_sessionPlayer_canResume_destroyedWhileActive_setToResume() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)
        addPlaybackStateAction()

        // When a media control using session actions and that does allow resumption is added,
        addNotificationAndLoad()
        val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
        mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)

        // And then the session is destroyed without timing out first
        sessionCallbackCaptor.value.invoke(KEY)

        // It is converted to a resume player
        verify(listener)
            .onMediaDataLoaded(
                eq(PACKAGE_NAME),
                eq(KEY),
                capture(mediaDataCaptor),
                eq(true),
                eq(0),
                eq(false),
            )
        assertThat(mediaDataCaptor.value.resumption).isTrue()
        assertThat(mediaDataCaptor.value.active).isFalse()
        verify(logger)
            .logActiveConvertedToResume(
                anyInt(),
                eq(PACKAGE_NAME),
                eq(mediaDataCaptor.value.instanceId),
            )
    }

    @Test
    fun testSessionPlayer_sessionDestroyed_noResume_fullyRemoved() {
        addPlaybackStateAction()
@@ -1937,19 +1729,6 @@ class LegacyMediaDataManagerImplTest(flags: FlagsParameterization) : SysuiTestCa
            )
    }

    @Test
    fun testSessionDestroyed_noNotificationKey_stillRemoved() {
        fakeFeatureFlags.set(MEDIA_RETAIN_SESSIONS, true)

        // When a notiifcation is added and then removed before it is fully processed
        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
        backgroundExecutor.runAllReady()
        mediaDataManager.onNotificationRemoved(KEY)

        // We still make sure to remove it
        verify(listener).onMediaDataRemoved(eq(KEY), eq(false))
    }

    @Test
    fun testResumeMediaLoaded_hasArtPermission_artLoaded() {
        // When resume media is loaded and user/app has permission to access the art URI,
Loading