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

Commit 8aee0382 authored by Andreas Miko's avatar Andreas Miko
Browse files

[Scene container] Transform KeyguardSurfaceBehindInteractor

Bug: 349784682
Flag: com.android.systemui.scene_container
Test: refactor / added unit tests
Change-Id: I477a24b0b456030e3ff1807f0c3721b1577216a7
parent 40bb68ba
Loading
Loading
Loading
Loading
+23 −12
Original line number Diff line number Diff line
@@ -19,9 +19,10 @@ package com.android.systemui.keyguard.domain.interactor
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor.Companion.isSurfaceVisible
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.kotlin.toPx
@@ -56,12 +57,18 @@ constructor(
     */
    val viewParams: Flow<KeyguardSurfaceBehindModel> =
        combine(
                transitionInteractor.startedKeyguardTransitionStep,
                transitionInteractor.currentKeyguardState,
                transitionInteractor.isInTransition(
                    Edge.create(to = Scenes.Gone),
                    edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE)
                ),
                transitionInteractor.isFinishedIn(
                    Scenes.Gone,
                    stateWithoutSceneContainer = KeyguardState.GONE
                ),
                notificationLaunchInteractor.isLaunchAnimationRunning,
            ) { startedStep, currentState, notifAnimationRunning ->
            ) { transitioningToGone, isOnGone, notifAnimationRunning ->
                // If we're in transition to GONE, special unlock animation params apply.
                if (startedStep.to == KeyguardState.GONE && currentState != KeyguardState.GONE) {
                if (transitioningToGone) {
                    if (notifAnimationRunning) {
                        // If the notification launch animation is running, leave the alpha at 0f.
                        // The ActivityLaunchAnimator will morph it from the notification at the
@@ -87,14 +94,14 @@ constructor(
                            animateFromTranslationY =
                                SURFACE_TRANSLATION_Y_DISTANCE_DP.toPx(context).toFloat(),
                            translationY = 0f,
                            startVelocity = swipeToDismissInteractor.dismissFling.value?.velocity
                                    ?: 0f,
                            startVelocity =
                                swipeToDismissInteractor.dismissFling.value?.velocity ?: 0f,
                        )
                    }
                }

                // Default to the visibility of the current state, with no animations.
                KeyguardSurfaceBehindModel(alpha = if (isSurfaceVisible(currentState)) 1f else 0f)
                KeyguardSurfaceBehindModel(alpha = if (isOnGone) 1f else 0f)
            }
            .distinctUntilChanged()

@@ -103,10 +110,14 @@ constructor(
     */
    private val isNotificationLaunchAnimationRunningOnKeyguard =
        notificationLaunchInteractor.isLaunchAnimationRunning
            .sample(transitionInteractor.finishedKeyguardState, ::Pair)
            .map { (animationRunning, finishedState) ->
                animationRunning && finishedState != KeyguardState.GONE
            }
            .sample(
                transitionInteractor.isFinishedIn(
                    Scenes.Gone,
                    stateWithoutSceneContainer = KeyguardState.GONE
                ),
                ::Pair
            )
            .map { (animationRunning, isOnGone) -> animationRunning && !isOnGone }
            .onStart { emit(false) }

    /**
+164 −5
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
@@ -28,12 +31,18 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.mockTopActivityClassName
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.shared.system.activityManagerWrapper
import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.assertValuesMatch
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -44,16 +53,22 @@ import org.junit.runner.RunWith
@kotlinx.coroutines.ExperimentalCoroutinesApi
class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val underTest = kosmos.keyguardSurfaceBehindInteractor
    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
    private val inWindowUnlockInteractor = kosmos.inWindowLauncherUnlockAnimationInteractor
    private val activityManagerWrapper = kosmos.activityManagerWrapper
    private lateinit var testScope: TestScope
    private lateinit var underTest: KeyguardSurfaceBehindInteractor
    private lateinit var transitionRepository: FakeKeyguardTransitionRepository
    private lateinit var inWindowUnlockInteractor: InWindowLauncherUnlockAnimationInteractor
    private lateinit var activityManagerWrapper: ActivityManagerWrapper

    private val LAUNCHER_ACTIVITY_NAME = "launcher"

    @Before
    fun setUp() {
        testScope = kosmos.testScope
        underTest = kosmos.keyguardSurfaceBehindInteractor
        transitionRepository = kosmos.fakeKeyguardTransitionRepository
        inWindowUnlockInteractor = kosmos.inWindowLauncherUnlockAnimationInteractor
        activityManagerWrapper = kosmos.activityManagerWrapper

        inWindowUnlockInteractor.setLauncherActivityClass(LAUNCHER_ACTIVITY_NAME)

        // Default to having something other than Launcher on top.
@@ -61,6 +76,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
    }

    @Test
    @DisableSceneContainer
    fun testSurfaceBehindModel_toAppSurface() =
        testScope.runTest {
            val values by collectValues(underTest.viewParams)
@@ -136,6 +152,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun testSurfaceBehindModel_toLauncher() =
        testScope.runTest {
            val values by collectValues(underTest.viewParams)
@@ -196,6 +213,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun testSurfaceBehindModel_fromNotificationLaunch() =
        testScope.runTest {
            val values by collectValues(underTest.viewParams)
@@ -230,6 +248,105 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
        }

    @Test
    @EnableSceneContainer
    fun testSurfaceBehindModel_toAppSurface_scene_container() =
        testScope.runTest {
            val values by collectValues(underTest.viewParams)
            runCurrent()

            assertThat(values)
                .containsExactly(
                    // We're initialized in LOCKSCREEN.
                    KeyguardSurfaceBehindModel(alpha = 0f),
                )

            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))

            values.assertValuesMatch(
                { it == KeyguardSurfaceBehindModel(alpha = 0f) },
                // Once we start a transition to GONE, we should fade in and translate up. The exact
                // start value depends on screen density, so just look for != 0.
                {
                    it.animateFromAlpha == 0f &&
                        it.alpha == 1f &&
                        it.animateFromTranslationY != 0f &&
                        it.translationY == 0f
                }
            )

            kosmos.setSceneTransition(Idle(Scenes.Gone))

            values.assertValuesMatch(
                { it == KeyguardSurfaceBehindModel(alpha = 0f) },
                {
                    it.animateFromAlpha == 0f &&
                        it.alpha == 1f &&
                        it.animateFromTranslationY != 0f &&
                        it.translationY == 0f
                },
                // Once the current state is GONE, we should default to alpha = 1f.
                { it == KeyguardSurfaceBehindModel(alpha = 1f) }
            )
        }

    @Test
    @EnableSceneContainer
    fun testSurfaceBehindModel_toLauncher_scene_container() =
        testScope.runTest {
            val values by collectValues(underTest.viewParams)
            activityManagerWrapper.mockTopActivityClassName(LAUNCHER_ACTIVITY_NAME)
            runCurrent()

            assertThat(values)
                .containsExactly(
                    // We're initialized in LOCKSCREEN.
                    KeyguardSurfaceBehindModel(alpha = 0f),
                )
                .inOrder()

            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))

            assertThat(values)
                .containsExactly(
                    KeyguardSurfaceBehindModel(alpha = 0f),
                    // We should instantly set alpha = 1, with no animations, when Launcher is
                    // behind
                    // the keyguard since we're playing in-window animations.
                    KeyguardSurfaceBehindModel(alpha = 1f),
                )
                .inOrder()

            kosmos.setSceneTransition(Idle(Scenes.Gone))

            assertThat(values)
                .containsExactly(
                    KeyguardSurfaceBehindModel(alpha = 0f),
                    // Should have remained at alpha = 1f through the entire animation.
                    KeyguardSurfaceBehindModel(alpha = 1f),
                )
                .inOrder()
        }

    @Test
    @EnableSceneContainer
    fun testSurfaceBehindModel_fromNotificationLaunch_scene_container() =
        testScope.runTest {
            val values by collectValues(underTest.viewParams)
            runCurrent()

            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
            runCurrent()

            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))

            values.assertValuesMatch(
                // We should be at alpha = 0f during the animation.
                { it == KeyguardSurfaceBehindModel(alpha = 0f) },
            )
        }

    @Test
    @DisableSceneContainer
    fun notificationLaunchFromLockscreen_isAnimatingSurfaceTrue() =
        testScope.runTest {
            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -253,6 +370,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun notificationLaunchFromGone_isAnimatingSurfaceFalse() =
        testScope.runTest {
            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -276,6 +394,7 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun notificationLaunchFalse_isAnimatingSurfaceFalse() =
        testScope.runTest {
            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -297,4 +416,44 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
            runCurrent()
            assertThat(isAnimatingSurface).isFalse()
        }

    @Test
    @EnableSceneContainer
    fun notificationLaunchFromLockscreen_isAnimatingSurfaceTrue_scene_container() =
        testScope.runTest {
            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)

            kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
            runCurrent()

            assertThat(isAnimatingSurface).isTrue()
        }

    @Test
    @EnableSceneContainer
    fun notificationLaunchFromGone_isAnimatingSurfaceFalse_scene_container() =
        testScope.runTest {
            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)

            kosmos.setSceneTransition(Idle(Scenes.Gone))
            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
            runCurrent()
            assertThat(isAnimatingSurface).isFalse()

            kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
            assertThat(isAnimatingSurface).isFalse()
        }

    @Test
    @EnableSceneContainer
    fun notificationLaunchFalse_isAnimatingSurfaceFalse_scene_container() =
        testScope.runTest {
            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)

            kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
            runCurrent()
            assertThat(isAnimatingSurface).isFalse()
        }
}