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

Commit 12281f86 authored by Michael Mikhail's avatar Michael Mikhail Committed by Automerger Merge Worker
Browse files

Merge "Hide resume players on entering the lockdown mode" into tm-qpr-dev am: 561bd764

parents 0b0651eb 561bd764
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,10 @@ class KeyguardTransitionInteractor
constructor(
constructor(
    repository: KeyguardTransitionRepository,
    repository: KeyguardTransitionRepository,
) {
) {
    /** (any)->GONE transition information */
    val anyStateToGoneTransition: Flow<TransitionStep> =
        repository.transitions.filter { step -> step.to == KeyguardState.GONE }

    /** (any)->AOD transition information */
    /** (any)->AOD transition information */
    val anyStateToAodTransition: Flow<TransitionStep> =
    val anyStateToAodTransition: Flow<TransitionStep> =
        repository.transitions.filter { step -> step.to == KeyguardState.AOD }
        repository.transitions.filter { step -> step.to == KeyguardState.AOD }
+7 −1
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@ import android.text.TextUtils
import android.util.Log
import android.util.Log
import androidx.media.utils.MediaConstants
import androidx.media.utils.MediaConstants
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.Dumpable
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -177,6 +178,7 @@ class MediaDataManager(
    private val mediaFlags: MediaFlags,
    private val mediaFlags: MediaFlags,
    private val logger: MediaUiEventLogger,
    private val logger: MediaUiEventLogger,
    private val smartspaceManager: SmartspaceManager,
    private val smartspaceManager: SmartspaceManager,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {


    companion object {
    companion object {
@@ -241,6 +243,7 @@ class MediaDataManager(
        mediaFlags: MediaFlags,
        mediaFlags: MediaFlags,
        logger: MediaUiEventLogger,
        logger: MediaUiEventLogger,
        smartspaceManager: SmartspaceManager,
        smartspaceManager: SmartspaceManager,
        keyguardUpdateMonitor: KeyguardUpdateMonitor,
    ) : this(
    ) : this(
        context,
        context,
        backgroundExecutor,
        backgroundExecutor,
@@ -264,6 +267,7 @@ class MediaDataManager(
        mediaFlags,
        mediaFlags,
        logger,
        logger,
        smartspaceManager,
        smartspaceManager,
        keyguardUpdateMonitor,
    )
    )


    private val appChangeReceiver =
    private val appChangeReceiver =
@@ -1336,7 +1340,9 @@ class MediaDataManager(
        Assert.isMainThread()
        Assert.isMainThread()
        val removed = mediaEntries.remove(key) ?: return
        val removed = mediaEntries.remove(key) ?: return


        if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
        if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
        } else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
            convertToResumePlayer(removed)
            convertToResumePlayer(removed)
        } else if (mediaFlags.isRetainingPlayersEnabled()) {
        } else if (mediaFlags.isRetainingPlayersEnabled()) {
            handlePossibleRemoval(removed, notificationRemoved = true)
            handlePossibleRemoval(removed, notificationRemoved = true)
+48 −0
Original line number Original line Diff line number Diff line
@@ -30,13 +30,20 @@ import android.view.ViewGroup
import android.view.animation.PathInterpolator
import android.view.animation.PathInterpolator
import android.widget.LinearLayout
import android.widget.LinearLayout
import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Dumpable
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
@@ -63,6 +70,10 @@ import java.io.PrintWriter
import java.util.TreeMap
import java.util.TreeMap
import javax.inject.Inject
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch


private const val TAG = "MediaCarouselController"
private const val TAG = "MediaCarouselController"
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
@@ -91,6 +102,8 @@ constructor(
    private val logger: MediaUiEventLogger,
    private val logger: MediaUiEventLogger,
    private val debugLogger: MediaCarouselControllerLogger,
    private val debugLogger: MediaCarouselControllerLogger,
    private val mediaFlags: MediaFlags,
    private val mediaFlags: MediaFlags,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : Dumpable {
) : Dumpable {
    /** The current width of the carousel */
    /** The current width of the carousel */
    private var currentCarouselWidth: Int = 0
    private var currentCarouselWidth: Int = 0
@@ -213,6 +226,17 @@ constructor(
            }
            }
        }
        }


    private val keyguardUpdateMonitorCallback =
        object : KeyguardUpdateMonitorCallback() {
            override fun onStrongAuthStateChanged(userId: Int) {
                if (keyguardUpdateMonitor.isUserInLockdown(userId)) {
                    hideMediaCarousel()
                } else if (keyguardUpdateMonitor.isUserUnlocked(userId)) {
                    showMediaCarousel()
                }
            }
        }

    /**
    /**
     * Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility.
     * Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility.
     * It will be called when the container is out of view.
     * It will be called when the container is out of view.
@@ -487,6 +511,13 @@ constructor(
                }
                }
            }
            }
        )
        )
        keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
        mediaCarousel.repeatWhenAttached {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                // A backup to show media carousel (if available) once the keyguard is gone.
                listenForAnyStateToGoneKeyguardTransition(this)
            }
        }
    }
    }


    private fun inflateSettingsButton() {
    private fun inflateSettingsButton() {
@@ -516,6 +547,23 @@ constructor(
        return mediaCarousel
        return mediaCarousel
    }
    }


    private fun hideMediaCarousel() {
        mediaCarousel.visibility = View.GONE
    }

    private fun showMediaCarousel() {
        mediaCarousel.visibility = View.VISIBLE
    }

    @VisibleForTesting
    internal fun listenForAnyStateToGoneKeyguardTransition(scope: CoroutineScope): Job {
        return scope.launch {
            keyguardTransitionInteractor.anyStateToGoneTransition
                .filter { it.transitionState == TransitionState.FINISHED }
                .collect { showMediaCarousel() }
        }
    }

    private fun reorderAllPlayers(
    private fun reorderAllPlayers(
        previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?,
        previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?,
        key: String? = null
        key: String? = null
+17 −0
Original line number Original line Diff line number Diff line
@@ -40,6 +40,7 @@ import android.testing.TestableLooper.RunWithLooper
import androidx.media.utils.MediaConstants
import androidx.media.utils.MediaConstants
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
@@ -126,6 +127,7 @@ class MediaDataManagerTest : SysuiTestCase() {
    @Mock lateinit var pendingIntent: PendingIntent
    @Mock lateinit var pendingIntent: PendingIntent
    @Mock lateinit var activityStarter: ActivityStarter
    @Mock lateinit var activityStarter: ActivityStarter
    @Mock lateinit var smartspaceManager: SmartspaceManager
    @Mock lateinit var smartspaceManager: SmartspaceManager
    @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
    lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
    lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
    @Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
    @Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
    @Mock private lateinit var mediaRecommendationItem: SmartspaceAction
    @Mock private lateinit var mediaRecommendationItem: SmartspaceAction
@@ -187,6 +189,7 @@ class MediaDataManagerTest : SysuiTestCase() {
                mediaFlags = mediaFlags,
                mediaFlags = mediaFlags,
                logger = logger,
                logger = logger,
                smartspaceManager = smartspaceManager,
                smartspaceManager = smartspaceManager,
                keyguardUpdateMonitor = keyguardUpdateMonitor
            )
            )
        verify(tunerService)
        verify(tunerService)
            .addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
            .addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
@@ -242,6 +245,7 @@ class MediaDataManagerTest : SysuiTestCase() {
        whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false)
        whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false)
        whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
        whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
        whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
        whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
        whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(false)
    }
    }


    @After
    @After
@@ -682,6 +686,19 @@ class MediaDataManagerTest : SysuiTestCase() {
        verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME"))
        verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME"))
    }
    }


    fun testOnNotificationRemoved_lockDownMode() {
        whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(true)

        addNotificationAndLoad()
        val data = mediaDataCaptor.value
        mediaDataManager.onNotificationRemoved(KEY)

        verify(listener, never()).onMediaDataRemoved(eq(KEY))
        verify(logger, never())
            .logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
        verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
    }

    @Test
    @Test
    fun testAddResumptionControls() {
    fun testAddResumptionControls() {
        // WHEN resumption controls are added
        // WHEN resumption controls are added
+56 −0
Original line number Original line Diff line number Diff line
@@ -21,12 +21,20 @@ import android.content.res.Configuration
import android.testing.AndroidTestingRunner
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper
import android.util.MathUtils.abs
import android.util.MathUtils.abs
import android.view.View
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
@@ -49,6 +57,9 @@ import javax.inject.Provider
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import junit.framework.Assert.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Before
import org.junit.Ignore
import org.junit.Ignore
import org.junit.Test
import org.junit.Test
@@ -90,11 +101,15 @@ class MediaCarouselControllerTest : SysuiTestCase() {
    @Mock lateinit var mediaCarousel: MediaScrollView
    @Mock lateinit var mediaCarousel: MediaScrollView
    @Mock lateinit var pageIndicator: PageIndicator
    @Mock lateinit var pageIndicator: PageIndicator
    @Mock lateinit var mediaFlags: MediaFlags
    @Mock lateinit var mediaFlags: MediaFlags
    @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
    @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
    private lateinit var transitionRepository: FakeKeyguardTransitionRepository
    @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
    @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
    @Captor
    @Captor
    lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
    lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
    @Captor lateinit var newConfig: ArgumentCaptor<Configuration>
    @Captor lateinit var newConfig: ArgumentCaptor<Configuration>
    @Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
    @Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
    @Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>


    private val clock = FakeSystemClock()
    private val clock = FakeSystemClock()
    private lateinit var mediaCarouselController: MediaCarouselController
    private lateinit var mediaCarouselController: MediaCarouselController
@@ -102,6 +117,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
    @Before
    @Before
    fun setup() {
    fun setup() {
        MockitoAnnotations.initMocks(this)
        MockitoAnnotations.initMocks(this)
        transitionRepository = FakeKeyguardTransitionRepository()
        mediaCarouselController =
        mediaCarouselController =
            MediaCarouselController(
            MediaCarouselController(
                context,
                context,
@@ -119,11 +135,14 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                logger,
                logger,
                debugLogger,
                debugLogger,
                mediaFlags,
                mediaFlags,
                keyguardUpdateMonitor,
                KeyguardTransitionInteractor(repository = transitionRepository),
            )
            )
        verify(configurationController).addCallback(capture(configListener))
        verify(configurationController).addCallback(capture(configListener))
        verify(mediaDataManager).addListener(capture(listener))
        verify(mediaDataManager).addListener(capture(listener))
        verify(visualStabilityProvider)
        verify(visualStabilityProvider)
            .addPersistentReorderingAllowedListener(capture(visualStabilityCallback))
            .addPersistentReorderingAllowedListener(capture(visualStabilityCallback))
        verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCallback))
        whenever(mediaControlPanelFactory.get()).thenReturn(panel)
        whenever(mediaControlPanelFactory.get()).thenReturn(panel)
        whenever(panel.mediaViewController).thenReturn(mediaViewController)
        whenever(panel.mediaViewController).thenReturn(mediaViewController)
        whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
        whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
@@ -740,4 +759,41 @@ class MediaCarouselControllerTest : SysuiTestCase() {
        assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(0).isSsMediaRec)
        assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(0).isSsMediaRec)
        assertFalse(MediaPlayerData.visiblePlayerKeys().elementAt(0).data.active)
        assertFalse(MediaPlayerData.visiblePlayerKeys().elementAt(0).data.active)
    }
    }

    @Test
    fun testOnLockDownMode_hideMediaCarousel() {
        whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(true)
        mediaCarouselController.mediaCarousel = mediaCarousel

        keyguardCallback.value.onStrongAuthStateChanged(context.userId)

        verify(mediaCarousel).visibility = View.GONE
    }

    @Test
    fun testLockDownModeOff_showMediaCarousel() {
        whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(false)
        whenever(keyguardUpdateMonitor.isUserUnlocked(context.userId)).thenReturn(true)
        mediaCarouselController.mediaCarousel = mediaCarousel

        keyguardCallback.value.onStrongAuthStateChanged(context.userId)

        verify(mediaCarousel).visibility = View.VISIBLE
    }

    @ExperimentalCoroutinesApi
    @Test
    fun testKeyguardGone_showMediaCarousel() =
        runTest(UnconfinedTestDispatcher()) {
            mediaCarouselController.mediaCarousel = mediaCarousel

            val job = mediaCarouselController.listenForAnyStateToGoneKeyguardTransition(this)
            transitionRepository.sendTransitionStep(
                TransitionStep(to = KeyguardState.GONE, transitionState = TransitionState.FINISHED)
            )

            verify(mediaCarousel).visibility = View.VISIBLE

            job.cancel()
        }
}
}