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

Commit 25faa39d authored by Josh Tsuji's avatar Josh Tsuji Committed by Android (Google) Code Review
Browse files

Merge "Cache isLauncherUnderneath and update when finished in not-GONE." into main

parents 3cb96612 98f8de33
Loading
Loading
Loading
Loading
+57 −118
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
        InWindowLauncherUnlockAnimationInteractor(
            kosmos.inWindowLauncherUnlockAnimationRepository,
            kosmos.applicationCoroutineScope,
            kosmos.applicationCoroutineScope,
            kosmos.keyguardTransitionInteractor,
            { kosmos.keyguardSurfaceBehindRepository },
            kosmos.activityManagerWrapper,
@@ -73,29 +74,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
    @Test
    fun testTransitioningToGoneWithInWindowAnimation_trueIfTopActivityIsLauncher_andTransitioningToGone() =
        testScope.runTest {
            transitionToGoneThenLockscreen(withLauncherUnderneath = true)

            val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
            runCurrent()

            assertEquals(
                listOf(
                    false, // False by default.
                    false // False by default.
                ),
                values
            )

            // Put launcher on top
            kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
                launcherClassName
                values,
            )
            activityManagerWrapper.mockTopActivityClassName(launcherClassName)
            runCurrent()

            // Should still be false since we're not transitioning to GONE.
            assertEquals(
                listOf(
                    false, // False by default.
                    false // False by default.
                ),
                values
                values,
            )

            transitionRepository.sendTransitionStep(
@@ -112,7 +108,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
                    false,
                    true, // -> GONE + launcher is behind
                ),
                values
                values,
            )

            activityManagerWrapper.mockTopActivityClassName("not_launcher")
@@ -131,7 +127,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
                    true, // Top activity should be sampled, if it changes midway it should not
                    // matter.
                ),
                values
                values,
            )

            transitionRepository.sendTransitionStep(
@@ -149,35 +145,23 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
                    true,
                    false, // False once we're not transitioning anymore.
                ),
                values
                values,
            )
        }

    @Test
    fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherPartwayThrough() =
        testScope.runTest {
            val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
            runCurrent()

            assertEquals(
                listOf(
                    false, // False by default.
                ),
                values
            )
            transitionToGoneThenLockscreen(withLauncherUnderneath = false)

            // Put not launcher on top
            kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
                launcherClassName
            )
            activityManagerWrapper.mockTopActivityClassName("not_launcher")
            val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
            runCurrent()

            assertEquals(
                listOf(
                    false,
                    false // False by default.
                ),
                values
                values,
            )

            transitionRepository.sendTransitionStep(
@@ -189,12 +173,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            )
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
            )
            assertEquals(listOf(false), values)

            activityManagerWrapper.mockTopActivityClassName(launcherClassName)
            transitionRepository.sendTransitionStep(
@@ -206,12 +185,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            )
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
            )
            assertEquals(listOf(false), values)

            transitionRepository.sendTransitionStep(
                TransitionStep(
@@ -222,39 +196,21 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            )
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
            )
            assertEquals(listOf(false), values)
        }

    @Test
    fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherWhileNotTransitioningToGone() =
        testScope.runTest {
            transitionToGoneThenLockscreen(withLauncherUnderneath = true)
            val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
            runCurrent()

            assertEquals(
                listOf(
                    false, // False by default.
                    false // False by default.
                ),
                values
            )

            // Put launcher on top
            kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
                launcherClassName
            )
            activityManagerWrapper.mockTopActivityClassName(launcherClassName)
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
                values,
            )

            transitionRepository.sendTransitionStep(
@@ -266,32 +222,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            )
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
            )
            assertEquals(listOf(false), values)
        }

    @Test
    fun testShouldStartInWindowAnimation_trueOnceSurfaceAvailable_falseWhenTransitionEnds() =
        testScope.runTest {
            transitionToGoneThenLockscreen(withLauncherUnderneath = true)

            val values by collectValues(underTest.shouldStartInWindowAnimation)
            runCurrent()

            assertEquals(
                listOf(
                    false, // False by default.
                    false // False by default.
                ),
                values
                values,
            )

            // Put Launcher on top and begin transitioning to GONE.
            kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
                launcherClassName
            )
            activityManagerWrapper.mockTopActivityClassName(launcherClassName)
            transitionRepository.sendTransitionStep(
                TransitionStep(
                    transitionState = TransitionState.STARTED,
@@ -301,12 +249,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            )
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
            )
            assertEquals(listOf(false), values)

            kosmos.keyguardSurfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true)
            runCurrent()
@@ -316,7 +259,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
                    false,
                    true, // The surface is now available, so we should start the animation.
                ),
                values
                values,
            )

            transitionRepository.sendTransitionStep(
@@ -328,34 +271,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            )
            runCurrent()

            assertEquals(
                listOf(
                    false,
                    true,
                    false,
                ),
                values
            )
            assertEquals(listOf(false, true, false), values)
        }

    @Test
    fun testShouldStartInWindowAnimation_neverTrueIfSurfaceNotAvailable() =
        testScope.runTest {
            transitionToGoneThenLockscreen(withLauncherUnderneath = true)

            val values by collectValues(underTest.shouldStartInWindowAnimation)
            runCurrent()

            assertEquals(
                listOf(
                    false, // False by default.
                    false // False by default.
                ),
                values
                values,
            )

            // Put Launcher on top and begin transitioning to GONE.
            kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
                launcherClassName
            )
            activityManagerWrapper.mockTopActivityClassName(launcherClassName)
            transitionRepository.sendTransitionStep(
                TransitionStep(
                    transitionState = TransitionState.STARTED,
@@ -372,32 +305,23 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            )
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
            )
            assertEquals(listOf(false), values)
        }

    @Test
    fun testShouldStartInWindowAnimation_falseIfSurfaceAvailable_afterTransitionInterrupted() =
        testScope.runTest {
            transitionToGoneThenLockscreen(withLauncherUnderneath = true)
            val values by collectValues(underTest.shouldStartInWindowAnimation)
            runCurrent()

            assertEquals(
                listOf(
                    false, // False by default.
                    false // False by default.
                ),
                values
                values,
            )

            // Put Launcher on top and begin transitioning to GONE.
            kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
                launcherClassName
            )
            activityManagerWrapper.mockTopActivityClassName(launcherClassName)
            transitionRepository.sendTransitionStep(
                TransitionStep(
                    transitionState = TransitionState.STARTED,
@@ -422,11 +346,26 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
            kosmos.keyguardSurfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true)
            runCurrent()

            assertEquals(
                listOf(
                    false,
                ),
                values
            assertEquals(listOf(false), values)
        }

    /** Transitions to GONE from LOCKSCREEN after setting launcher underneath (or not). */
    private suspend fun transitionToGoneThenLockscreen(withLauncherUnderneath: Boolean) {
        transitionRepository.sendTransitionSteps(
            from = KeyguardState.LOCKSCREEN,
            to = KeyguardState.GONE,
            testScope,
        )

        kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(launcherClassName)
        activityManagerWrapper.mockTopActivityClassName(
            if (withLauncherUnderneath) launcherClassName else "not_launcher"
        )

        transitionRepository.sendTransitionSteps(
            from = KeyguardState.GONE,
            to = KeyguardState.LOCKSCREEN,
            testScope,
        )
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@ class InWindowLauncherUnlockAnimationRepository @Inject constructor() {
     */
    val launcherSmartspaceState: MutableStateFlow<SmartspaceState?> = MutableStateFlow(null)

    val isLauncherUnderneath: MutableStateFlow<Boolean> = MutableStateFlow(false)

    fun setStartedUnlockAnimation(started: Boolean) {
        startedUnlockAnimation.value = started
    }
@@ -86,4 +88,8 @@ class InWindowLauncherUnlockAnimationRepository @Inject constructor() {
    fun setLauncherSmartspaceState(state: SmartspaceState?) {
        launcherSmartspaceState.value = state
    }

    fun setIsLauncherUnderneath(isUnderneath: Boolean) {
        isLauncherUnderneath.value = isUnderneath
    }
}
+40 −6
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.shared.model.Edge
@@ -31,8 +32,10 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

@SysUISingleton
class InWindowLauncherUnlockAnimationInteractor
@@ -40,6 +43,7 @@ class InWindowLauncherUnlockAnimationInteractor
constructor(
    private val repository: InWindowLauncherUnlockAnimationRepository,
    @Application scope: CoroutineScope,
    @Background val backgroundScope: CoroutineScope,
    transitionInteractor: KeyguardTransitionInteractor,
    surfaceBehindRepository: dagger.Lazy<KeyguardSurfaceBehindRepository>,
    private val activityManager: ActivityManagerWrapper,
@@ -54,7 +58,7 @@ constructor(
        transitionInteractor
            .isInTransition(
                edge = Edge.create(to = Scenes.Gone),
                edgeWithoutSceneContainer = Edge.create(to = GONE)
                edgeWithoutSceneContainer = Edge.create(to = GONE),
            )
            .map { transitioningToGone -> transitioningToGone && isLauncherUnderneath() }
            .stateIn(scope, SharingStarted.Eagerly, false)
@@ -74,6 +78,25 @@ constructor(
            }
            .stateIn(scope, SharingStarted.Eagerly, false)

    init {
        backgroundScope.launch {
            // Whenever we're not GONE, update whether Launcher was the app in front. We need to do
            // this before the next unlock, but it triggers a binder call, so this is the best time
            // to do it. In edge cases where this changes while we're locked (the foreground app
            // crashes, etc.) the worst case is that we fall back to the normal unlock animation (or
            // unnecessarily play the animation on Launcher when there's an app over it), which is
            // not a big deal.
            transitionInteractor.currentKeyguardState
                .map { it != GONE }
                .distinctUntilChanged()
                .collect { notOnGone ->
                    if (notOnGone) {
                        updateIsLauncherUnderneath()
                    }
                }
        }
    }

    /** Sets whether we've started */
    fun setStartedUnlockAnimation(started: Boolean) {
        repository.setStartedUnlockAnimation(started)
@@ -92,13 +115,24 @@ constructor(
    }

    /**
     * Whether the Launcher is currently underneath the lockscreen (it's at the top of the activity
     * task stack).
     * Whether the Launcher was underneath the lockscreen as of the last time we locked (it's at the
     * top of the activity task stack).
     */
    fun isLauncherUnderneath(): Boolean {
        return repository.launcherActivityClass.value?.let {
        return repository.isLauncherUnderneath.value
    }

    /**
     * Updates whether Launcher is the app underneath the lock screen as of this moment. Triggers a
     * binder call, so this is run in the background.
     */
    private fun updateIsLauncherUnderneath() {
        backgroundScope.launch {
            repository.setIsLauncherUnderneath(
                repository.launcherActivityClass.value?.let {
                    activityManager.runningTask?.topActivity?.className?.equals(it)
                } ?: false
            )
        }
            ?: false
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ val Kosmos.inWindowLauncherUnlockAnimationInteractor by
        InWindowLauncherUnlockAnimationInteractor(
            repository = inWindowLauncherUnlockAnimationRepository,
            scope = applicationCoroutineScope,
            backgroundScope = applicationCoroutineScope,
            transitionInteractor = keyguardTransitionInteractor,
            surfaceBehindRepository = Lazy { keyguardSurfaceBehindRepository },
            activityManager = activityManagerWrapper,