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

Commit 544725f5 authored by Beverly's avatar Beverly Committed by Beverly Tai
Browse files

Fix legacy udfps occluded state transitions

In the udfps legacy code, add support for
occluded <=> AOD transitions which were
previously unsupported and would put the udfps UI
in the wrong state.

Also fix the transition from AOD => Occluded after a cancellation
of a AOD => LS transition.
For example the following sequence of transitions when the user
is double pressing the power button to show the camera:
  START: AOD => Lockscreen (first power button press)
  CANCEL: AOD => Lockscreen (second power button press)
  START: Lockscreen => Occluded
In this case, ensure the doze amount is appropriately updated to 0f.

Test: atest SystemUITests
Test: atest UdfpsKeyguardViewLegacyControllerWithCoroutinesTest
Test: Show the camera app over the lockscreen & then transition
to AOD. Observe that the AOD udfps icon shows, not the LS version
Fixes: 313963031
Fixes: 313954401
Flag: NONE
Change-Id: I2b3c3759001dd51d4374456511d27f5552ec0b76

Change-Id: I055fee4ea35420211b6e68eb77130ab47864e3a0
parent 3fc09fe3
Loading
Loading
Loading
Loading
+123 −2
Original line number Diff line number Diff line
@@ -396,7 +396,7 @@ class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest :
                .onDozeAmountChanged(
                    eq(.3f),
                    eq(.3f),
                    eq(UdfpsKeyguardViewLegacy.ANIMATION_UNLOCKED_SCREEN_OFF)
                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
                )

            transitionRepository.sendTransitionStep(
@@ -413,9 +413,130 @@ class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest :
                .onDozeAmountChanged(
                    eq(1f),
                    eq(1f),
                    eq(UdfpsKeyguardViewLegacy.ANIMATION_UNLOCKED_SCREEN_OFF)
                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
                )

            job.cancel()
        }

    @Test
    fun aodToOccluded_dozeAmountChanged() =
        testScope.runTest {
            // GIVEN view is attached
            mController.onViewAttached()
            Mockito.reset(mView)

            val job = mController.listenForAodToOccludedTransitions(this)

            // WHEN transitioning from aod to occluded
            transitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.AOD,
                    to = KeyguardState.OCCLUDED,
                    value = .3f,
                    transitionState = TransitionState.RUNNING
                )
            )
            runCurrent()
            // THEN doze amount is updated
            verify(mView)
                .onDozeAmountChanged(eq(.7f), eq(.7f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE))

            transitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.AOD,
                    to = KeyguardState.OCCLUDED,
                    value = 1f,
                    transitionState = TransitionState.FINISHED
                )
            )
            runCurrent()
            // THEN doze amount is updated
            verify(mView)
                .onDozeAmountChanged(eq(0f), eq(0f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE))

            job.cancel()
        }

    @Test
    fun occludedToAod_dozeAmountChanged() =
        testScope.runTest {
            // GIVEN view is attached
            mController.onViewAttached()
            Mockito.reset(mView)

            val job = mController.listenForOccludedToAodTransition(this)

            // WHEN transitioning from occluded to aod
            transitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.OCCLUDED,
                    to = KeyguardState.AOD,
                    value = .3f,
                    transitionState = TransitionState.RUNNING
                )
            )
            runCurrent()
            // THEN doze amount is updated
            verify(mView)
                .onDozeAmountChanged(
                    eq(.3f),
                    eq(.3f),
                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
                )

            transitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.OCCLUDED,
                    to = KeyguardState.AOD,
                    value = 1f,
                    transitionState = TransitionState.FINISHED
                )
            )
            runCurrent()
            // THEN doze amount is updated
            verify(mView)
                .onDozeAmountChanged(
                    eq(1f),
                    eq(1f),
                    eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF)
                )

            job.cancel()
        }

    @Test
    fun cancelledAodToLockscreen_dozeAmountChangedToZero() =
        testScope.runTest {
            // GIVEN view is attached
            mController.onViewAttached()
            Mockito.reset(mView)

            val job = mController.listenForLockscreenAodTransitions(this)
            // WHEN aod to lockscreen transition is cancelled
            transitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.AOD,
                    to = KeyguardState.LOCKSCREEN,
                    value = 1f,
                    transitionState = TransitionState.CANCELED
                )
            )
            runCurrent()
            // ... and WHEN the next transition is from lockscreen => occluded
            transitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.LOCKSCREEN,
                    to = KeyguardState.OCCLUDED,
                    value = .4f,
                    transitionState = TransitionState.STARTED
                )
            )
            runCurrent()

            // THEN doze amount is updated to zero
            verify(mView)
                .onDozeAmountChanged(eq(0f), eq(0f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE))
            job.cancel()
        }
}
+55 −8
Original line number Diff line number Diff line
@@ -26,11 +26,13 @@ import com.android.app.animation.Interpolators
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATION_UNLOCKED_SCREEN_OFF
import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dump.DumpManager
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.ui.adapter.UdfpsKeyguardViewControllerAdapter
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -49,7 +51,7 @@ import java.io.PrintWriter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch

/** Class that coordinates non-HBM animations during keyguard authentication. */
@@ -191,8 +193,38 @@ open class UdfpsKeyguardViewControllerLegacy(
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                listenForBouncerExpansion(this)
                listenForAlternateBouncerVisibility(this)
                listenForOccludedToAodTransition(this)
                listenForGoneToAodTransition(this)
                listenForLockscreenAodTransitions(this)
                listenForAodToOccludedTransitions(this)
            }
        }
    }

    @VisibleForTesting
    suspend fun listenForAodToOccludedTransitions(scope: CoroutineScope): Job {
        return scope.launch {
            transitionInteractor.transition(KeyguardState.AOD, KeyguardState.OCCLUDED).collect {
                transitionStep ->
                view.onDozeAmountChanged(
                    1f - transitionStep.value,
                    1f - transitionStep.value,
                    UdfpsKeyguardViewLegacy.ANIMATION_NONE,
                )
            }
        }
    }

    @VisibleForTesting
    suspend fun listenForOccludedToAodTransition(scope: CoroutineScope): Job {
        return scope.launch {
            transitionInteractor.transition(KeyguardState.OCCLUDED, KeyguardState.AOD).collect {
                transitionStep ->
                view.onDozeAmountChanged(
                    transitionStep.value,
                    transitionStep.value,
                    ANIMATE_APPEAR_ON_SCREEN_OFF,
                )
            }
        }
    }
@@ -204,7 +236,7 @@ open class UdfpsKeyguardViewControllerLegacy(
                view.onDozeAmountChanged(
                    transitionStep.value,
                    transitionStep.value,
                    ANIMATION_UNLOCKED_SCREEN_OFF,
                    ANIMATE_APPEAR_ON_SCREEN_OFF,
                )
            }
        }
@@ -214,6 +246,20 @@ open class UdfpsKeyguardViewControllerLegacy(
    suspend fun listenForLockscreenAodTransitions(scope: CoroutineScope): Job {
        return scope.launch {
            transitionInteractor.dozeAmountTransition.collect { transitionStep ->
                if (transitionStep.transitionState == TransitionState.CANCELED) {
                    if (
                        transitionInteractor.startedKeyguardTransitionStep.first().to !=
                            KeyguardState.AOD
                    ) {
                        // If the next started transition isn't transitioning back to AOD, force
                        // doze amount to be 0f (as if the transition to the lockscreen completed).
                        view.onDozeAmountChanged(
                            0f,
                            0f,
                            UdfpsKeyguardViewLegacy.ANIMATION_NONE,
                        )
                    }
                } else {
                    view.onDozeAmountChanged(
                        transitionStep.value,
                        transitionStep.value,
@@ -222,6 +268,7 @@ open class UdfpsKeyguardViewControllerLegacy(
                }
            }
        }
    }

    @VisibleForTesting
    override suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job {
+4 −4
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ public class UdfpsKeyguardViewLegacy extends UdfpsAnimationView {

        // if we're animating from screen off, we can immediately place the icon in the
        // AoD-burn in location, else we need to translate the icon from LS => AoD.
        final float darkAmountForAnimation = mAnimationType == ANIMATION_UNLOCKED_SCREEN_OFF
        final float darkAmountForAnimation = mAnimationType == ANIMATE_APPEAR_ON_SCREEN_OFF
                ? 1f : mInterpolatedDarkAmount;
        final float burnInOffsetX = MathUtils.lerp(0f,
            getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
@@ -171,7 +171,7 @@ public class UdfpsKeyguardViewLegacy extends UdfpsAnimationView {
                mAnimationType == ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN
                        && (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f);
        final boolean doneAnimatingUnlockedScreenOff =
                mAnimationType == ANIMATION_UNLOCKED_SCREEN_OFF
                mAnimationType == ANIMATE_APPEAR_ON_SCREEN_OFF
                        && (mInterpolatedDarkAmount == 1f);
        if (doneAnimatingBetweenAodAndLS || doneAnimatingUnlockedScreenOff) {
            mAnimationType = ANIMATION_NONE;
@@ -243,10 +243,10 @@ public class UdfpsKeyguardViewLegacy extends UdfpsAnimationView {

    static final int ANIMATION_NONE = 0;
    static final int ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN = 1;
    static final int ANIMATION_UNLOCKED_SCREEN_OFF = 2;
    static final int ANIMATE_APPEAR_ON_SCREEN_OFF = 2;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({ANIMATION_NONE, ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, ANIMATION_UNLOCKED_SCREEN_OFF})
    @IntDef({ANIMATION_NONE, ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, ANIMATE_APPEAR_ON_SCREEN_OFF})
    private @interface AnimationType {}

    void onDozeAmountChanged(float linear, float eased, @AnimationType int animationType) {