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

Commit bb945dbb authored by Matt Pietal's avatar Matt Pietal
Browse files

Add AOD fold animation

When folding the device and entering AOD, keyguard
should fade in from the side and not the top as is
the default.

Bug: 346325723
Test: atest GoneToAodTransitionViewModelTest
Flag: com.android.systemui.migrate_clocks_to_blueprint
Change-Id: Ie754bf839c7121a3bd5a85a878c379021804e47c
parent 725aed7a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@ class AodBurnInViewModelTest : SysuiTestCase() {

    @Mock private lateinit var burnInInteractor: BurnInInteractor
    @Mock private lateinit var goneToAodTransitionViewModel: GoneToAodTransitionViewModel
    @Mock
    private lateinit var lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel
    @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var clockController: ClockController

    private val kosmos = testKosmos()
@@ -76,7 +78,12 @@ class AodBurnInViewModelTest : SysuiTestCase() {
        kosmos.burnInInteractor = burnInInteractor
        whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt()))
            .thenReturn(emptyFlow())
        whenever(goneToAodTransitionViewModel.enterFromSideTranslationX(anyInt()))
            .thenReturn(emptyFlow())
        whenever(lockscreenToAodTransitionViewModel.enterFromSideTranslationX(anyInt()))
            .thenReturn(emptyFlow())
        kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel
        kosmos.lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel
        kosmos.fakeKeyguardClockRepository.setCurrentClock(clockController)

        underTest = kosmos.aodBurnInViewModel
+86 −1
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.StateToValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.data.repository.powerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
@@ -47,10 +50,18 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() {
    private val underTest = kosmos.goneToAodTransitionViewModel
    private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
    private val biometricSettingsRepository = kosmos.biometricSettingsRepository
    private val powerRepository = kosmos.powerRepository

    @Test
    fun enterFromTopTranslationY() =
    fun enterFromTopTranslationY_whenNotOnFold() =
        testScope.runTest {
            powerRepository.updateWakefulness(
                rawState = WakefulnessState.STARTING_TO_SLEEP,
                lastWakeReason = WakeSleepReason.POWER_BUTTON,
                lastSleepReason = WakeSleepReason.POWER_BUTTON,
                powerButtonLaunchGestureTriggered = false
            )

            val pixels = -100f
            val enterFromTopTranslationY by
                collectLastValue(underTest.enterFromTopTranslationY(pixels.toInt()))
@@ -87,6 +98,80 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() {
                )
        }

    @Test
    fun enterFromTopTranslationY_whenOnFold_emitsNothing() =
        testScope.runTest {
            powerRepository.updateWakefulness(
                rawState = WakefulnessState.STARTING_TO_SLEEP,
                lastWakeReason = WakeSleepReason.POWER_BUTTON,
                lastSleepReason = WakeSleepReason.FOLD,
                powerButtonLaunchGestureTriggered = false
            )

            val pixels = -100f
            val enterFromTopTranslationY by
                collectLastValue(underTest.enterFromTopTranslationY(pixels.toInt()))
            runCurrent()

            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
            assertThat(enterFromTopTranslationY).isNull()

            repository.sendTransitionStep(step(.55f))
            assertThat(enterFromTopTranslationY).isNull()

            repository.sendTransitionStep(step(.85f))
            assertThat(enterFromTopTranslationY).isNull()

            repository.sendTransitionStep(step(1f))
            assertThat(enterFromTopTranslationY).isNull()
        }

    @Test
    fun enterFromSideTranslationX_onFold() =
        testScope.runTest {
            powerRepository.updateWakefulness(
                rawState = WakefulnessState.STARTING_TO_SLEEP,
                lastWakeReason = WakeSleepReason.POWER_BUTTON,
                lastSleepReason = WakeSleepReason.FOLD,
                powerButtonLaunchGestureTriggered = false
            )

            val pixels = -100f
            val enterFromSideTranslationX by
                collectLastValue(underTest.enterFromSideTranslationX(pixels.toInt()))
            runCurrent()

            // The animation should only start > .4f way through
            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
            assertThat(enterFromSideTranslationX)
                .isEqualTo(
                    StateToValue(
                        from = KeyguardState.GONE,
                        to = KeyguardState.AOD,
                        transitionState = TransitionState.STARTED,
                        value = pixels
                    )
                )

            repository.sendTransitionStep(step(.55f))
            assertThat(enterFromSideTranslationX!!.value ?: -1f).isIn(Range.closed(pixels, 0f))

            repository.sendTransitionStep(step(.85f))
            assertThat(enterFromSideTranslationX!!.value ?: -1f).isIn(Range.closed(pixels, 0f))

            // At the end, the translation should be complete and set to zero
            repository.sendTransitionStep(step(1f))
            assertThat(enterFromSideTranslationX)
                .isEqualTo(
                    StateToValue(
                        from = KeyguardState.GONE,
                        to = KeyguardState.AOD,
                        transitionState = TransitionState.RUNNING,
                        value = 0f
                    )
                )
        }

    @Test
    fun enterFromTopAnimationAlpha() =
        testScope.runTest {
+2 −0
Original line number Diff line number Diff line
@@ -810,6 +810,8 @@
    <dimen name="keyguard_smartspace_top_offset">12dp</dimen>
    <!-- The amount to translate lockscreen elements on the GONE->AOD transition -->
    <dimen name="keyguard_enter_from_top_translation_y">-100dp</dimen>
    <!-- The amount to translate lockscreen elements on the GONE->AOD transition, on device fold -->
    <dimen name="keyguard_enter_from_side_translation_x">-100dp</dimen>

    <dimen name="notification_scrim_corner_radius">32dp</dimen>

+8 −1
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason.FOLD
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
@@ -368,7 +369,12 @@ constructor(
                    // being delayed in KeyguardViewMediator
                    KeyguardState.DREAMING -> TO_DREAMING_DURATION + 100.milliseconds
                    KeyguardState.OCCLUDED -> TO_OCCLUDED_DURATION
                    KeyguardState.AOD -> TO_AOD_DURATION
                    KeyguardState.AOD ->
                        if (powerInteractor.detailedWakefulness.value.lastSleepReason == FOLD) {
                            TO_AOD_FOLD_DURATION
                        } else {
                            TO_AOD_DURATION
                        }
                    KeyguardState.DOZING -> TO_DOZING_DURATION
                    KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> TO_DREAMING_HOSTED_DURATION
                    KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION
@@ -385,6 +391,7 @@ constructor(
        val TO_DREAMING_HOSTED_DURATION = 933.milliseconds
        val TO_OCCLUDED_DURATION = 450.milliseconds
        val TO_AOD_DURATION = 500.milliseconds
        val TO_AOD_FOLD_DURATION = 1100.milliseconds
        val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
        val TO_GONE_DURATION = 633.milliseconds
        val TO_GLANCEABLE_HUB_DURATION = 1.seconds
+0 −29
Original line number Diff line number Diff line
@@ -16,30 +16,17 @@

package com.android.systemui.keyguard.domain.interactor

import android.animation.ValueAnimator
import android.view.ViewGroup
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.shade.ShadeFoldAnimator
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@SysUISingleton
class ToAodFoldTransitionInteractor
@Inject
constructor(
    private val keyguardClockInteractor: KeyguardClockInteractor,
    private val transitionInteractor: KeyguardTransitionInteractor,
    private val transitionRepository: KeyguardTransitionRepository,
    @Application private val mainScope: CoroutineScope,
    @Main private val mainDispatcher: CoroutineDispatcher,
) {
    private var parentAnimator: NotificationPanelViewController.ShadeFoldAnimatorImpl? = null

@@ -50,7 +37,6 @@ constructor(
                get() = throw NotImplementedError("Deprecated. Do not call.")

            override fun prepareFoldToAodAnimation() {
                forceToAod()
                parentAnimator?.prepareFoldToAodAnimation()
            }

@@ -78,21 +64,6 @@ constructor(
            parentAnimator as? NotificationPanelViewController.ShadeFoldAnimatorImpl?
    }

    /** Forces the keyguard into AOD or Doze */
    private fun forceToAod() {
        mainScope.launch(mainDispatcher) {
            transitionRepository.startTransition(
                TransitionInfo(
                    "$TAG (Fold transition triggered)",
                    transitionInteractor.getCurrentState(),
                    transitionInteractor.asleepKeyguardState.value,
                    ValueAnimator().apply { duration = 0 },
                    TransitionModeOnCanceled.LAST_VALUE,
                )
            )
        }
    }

    companion object {
        private val TAG = ToAodFoldTransitionInteractor::class.simpleName!!
    }
Loading