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

Commit 744ef308 authored by Matt Pietal's avatar Matt Pietal
Browse files

Fix GONE->AOD->GONE with timeout

In this case, the transitions were incorrectly going to LOCKSCREEN
when it needs to go to GONE. Fix this by combining all wake flows
from AOD in order to make the decision one time.

Fixes: 336800288
Test: atest FromAodTransitionInteractorTest
Flag: ACONFIG com.android.systemui.migrate_clocks_to_blueprint
TEAMFOOD

Change-Id: I527ac171906188545ddf083b26d2a15b61c0b892
parent 5e899586
Loading
Loading
Loading
Loading
+17 −21
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.os.PowerManager
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.lockPatternUtils
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -54,16 +53,15 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import junit.framework.Assert.assertEquals
import kotlin.test.Test
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.reset
import org.mockito.Mockito.spy

@@ -93,6 +91,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
        // Transition to AOD and set the power interactor asleep.
        powerInteractor.setAsleepForTest()
        runBlocking {
            kosmos.fakeKeyguardRepository.setKeyguardShowing(false)
            transitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.AOD,
@@ -108,7 +107,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
    fun testTransitionToLockscreen_onWakeup() =
        testScope.runTest {
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // Under default conditions, we should transition to LOCKSCREEN when waking up.
            assertThat(transitionRepository)
@@ -124,7 +123,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
        testScope.runTest {
            kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true)
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // Waking with a SHOW_WHEN_LOCKED activity on top should transition to OCCLUDED.
            assertThat(transitionRepository)
@@ -140,7 +139,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
        testScope.runTest {
            powerInteractor.onCameraLaunchGestureDetected()
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // We should head back to GONE since we started there.
            assertThat(transitionRepository)
@@ -154,7 +153,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
            kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
            powerInteractor.onCameraLaunchGestureDetected()
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // We should head back to GONE since we started there.
            assertThat(transitionRepository)
@@ -191,7 +190,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
            reset(transitionRepository)
            powerInteractor.onCameraLaunchGestureDetected()
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // We should head back to GONE since we started there.
            assertThat(transitionRepository)
@@ -225,7 +224,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
            reset(transitionRepository)
            powerInteractor.onCameraLaunchGestureDetected()
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // We should go to OCCLUDED - we came from GONE, but we finished in AOD, so this is no
            // longer an insecure camera launch and it would be bad if we unlocked now.
@@ -266,7 +265,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
            reset(transitionRepository)
            powerInteractor.onCameraLaunchGestureDetected()
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // We should head back to GONE since we started there.
            assertThat(transitionRepository)
@@ -286,7 +285,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
            assertThat(transitionRepository).noTransitionsStarted()

            underTest.dismissAod()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            assertThat(transitionRepository)
                .startedTransition(from = KeyguardState.AOD, to = KeyguardState.GONE)
@@ -297,7 +296,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
        testScope.runTest {
            kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
            powerInteractor.setAwakeForTest()
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // Waking up from AOD while occluded should transition to OCCLUDED.
            assertThat(transitionRepository)
@@ -307,11 +306,10 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
    @Test
    fun testTransitionToGone_onWakeUpFromAod_dismissibleKeyguard_securityNone() =
        testScope.runTest {
            whenever(kosmos.lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true)
            kosmos.fakeKeyguardRepository.setKeyguardShowing(false)
            kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
            powerInteractor.setAwakeForTest()
            testScope.testScheduler.advanceTimeBy(100) // account for debouncing
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // We should head back to GONE since we started there.
            assertThat(transitionRepository)
@@ -319,15 +317,13 @@ class FromAodTransitionInteractorTest : SysuiTestCase() {
        }

    @Test
    fun testTransitionToGone_onWakeUpFromAod_dismissibleKeyguard_securitySwipe() =
    fun testTransitionToLockscreen_onWakeUpFromAod_dismissibleKeyguard_securitySwipe() =
        testScope.runTest {
            whenever(kosmos.lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false)
            kosmos.fakeKeyguardRepository.setKeyguardShowing(true)
            kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
            powerInteractor.setAwakeForTest()
            testScope.testScheduler.advanceTimeBy(100) // account for debouncing
            runCurrent()
            advanceTimeBy(100) // account for debouncing

            // We should head back to GONE since we started there.
            assertThat(transitionRepository)
                .startedTransition(from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN)
        }
+21 −42
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.launch
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -29,12 +28,13 @@ import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce

@SysUISingleton
@@ -49,8 +49,6 @@ constructor(
    private val keyguardInteractor: KeyguardInteractor,
    powerInteractor: PowerInteractor,
    keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
    private val lockPatternUtils: LockPatternUtils,
    private val selectedUserInteractor: SelectedUserInteractor,
) :
    TransitionInteractor(
        fromState = KeyguardState.AOD,
@@ -65,10 +63,18 @@ constructor(
        listenForAodToAwake()
        listenForAodToOccluded()
        listenForAodToPrimaryBouncer()
        listenForAodToGone()
        listenForTransitionToCamera(scope, keyguardInteractor)
    }

    private val canDismissLockscreen: Flow<Boolean> =
        combine(
            keyguardInteractor.isKeyguardShowing,
            keyguardInteractor.isKeyguardDismissible,
            keyguardInteractor.biometricUnlockState,
        ) { isKeyguardShowing, isKeyguardDismissible, biometricUnlockState ->
            (isWakeAndUnlock(biometricUnlockState) || (!isKeyguardShowing && isKeyguardDismissible))
        }

    /**
     * Listen for the signal that we're waking up and figure what state we need to transition to.
     */
@@ -79,12 +85,13 @@ constructor(
        scope.launch("$TAG#listenForAodToAwake") {
            powerInteractor.detailedWakefulness
                .filterRelevantKeyguardStateAnd { wakefulness -> wakefulness.isAwake() }
                .debounce(50L)
                .sample(
                    startedKeyguardTransitionStep,
                    keyguardInteractor.biometricUnlockState,
                    keyguardInteractor.primaryBouncerShowing,
                    keyguardInteractor.isKeyguardOccluded,
                    selectedUserInteractor.selectedUser,
                    canDismissLockscreen,
                )
                .collect {
                    (
@@ -93,10 +100,9 @@ constructor(
                        biometricUnlockState,
                        primaryBouncerShowing,
                        isKeyguardOccludedLegacy,
                        currentUser,
                        canDismissLockscreen,
                    ) ->
                    if (!maybeHandleInsecurePowerGesture()) {
                        val securityNone = lockPatternUtils.isLockScreenDisabled(currentUser)
                        val shouldTransitionToLockscreen =
                            if (KeyguardWmStateRefactor.isEnabled) {
                                // Check with the superclass to see if an occlusion transition is
@@ -105,13 +111,11 @@ constructor(
                                // completes.
                                !maybeStartTransitionToOccludedOrInsecureCamera() &&
                                    !isWakeAndUnlock(biometricUnlockState) &&
                                    !primaryBouncerShowing &&
                                    !securityNone
                                    !primaryBouncerShowing
                            } else {
                                !isKeyguardOccludedLegacy &&
                                    !isWakeAndUnlock(biometricUnlockState) &&
                                    !primaryBouncerShowing &&
                                    !securityNone
                                    !primaryBouncerShowing
                            }

                        // With the refactor enabled, maybeStartTransitionToOccludedOrInsecureCamera
@@ -119,7 +123,11 @@ constructor(
                        val shouldTransitionToOccluded =
                            !KeyguardWmStateRefactor.isEnabled && isKeyguardOccludedLegacy

                        if (shouldTransitionToLockscreen) {
                        if (canDismissLockscreen) {
                            startTransitionTo(
                                toState = KeyguardState.GONE,
                            )
                        } else if (shouldTransitionToLockscreen) {
                            val modeOnCanceled =
                                if (startedStep.from == KeyguardState.LOCKSCREEN) {
                                    TransitionModeOnCanceled.REVERSE
@@ -181,35 +189,6 @@ constructor(
        }
    }

    private fun listenForAodToGone() {
        if (KeyguardWmStateRefactor.isEnabled) {
            // Handled via #dismissAod.
            return
        }

        scope.launch("$TAG#listenForAodToGone") {
            powerInteractor.isAwake
                .debounce(50L)
                .filterRelevantKeyguardState()
                .sample(
                    keyguardInteractor.biometricUnlockState,
                    keyguardInteractor.isKeyguardShowing,
                    keyguardInteractor.isKeyguardDismissible,
                )
                .collect { (isAwake, biometricUnlockState, isKeyguardShowing, isKeyguardDismissible)
                    ->
                    KeyguardWmStateRefactor.assertInLegacyMode()
                    if (
                        isAwake &&
                            (isWakeAndUnlock(biometricUnlockState) ||
                                (!isKeyguardShowing && isKeyguardDismissible))
                    ) {
                        startTransitionTo(KeyguardState.GONE)
                    }
                }
        }
    }

    /**
     * Dismisses AOD and transitions to GONE. This is called whenever authentication occurs while on
     * AOD.
+0 −6
Original line number Diff line number Diff line
@@ -100,12 +100,6 @@ constructor(
            keyguardInteractor.isDozing.collect { logger.log(TAG, VERBOSE, "isDozing", it) }
        }

        scope.launch {
            keyguardInteractor.isKeyguardDismissible.collect {
                logger.log(TAG, VERBOSE, "isKeyguardDismissable", it)
            }
        }

        scope.launch {
            keyguardInteractor.isAbleToDream.collect {
                logger.log(TAG, VERBOSE, "isAbleToDream", it)
+0 −4
Original line number Diff line number Diff line
@@ -16,14 +16,12 @@

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

import com.android.internal.widget.lockPatternUtils
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.user.domain.interactor.selectedUserInteractor

val Kosmos.fromAodTransitionInteractor by
    Kosmos.Fixture {
@@ -36,7 +34,5 @@ val Kosmos.fromAodTransitionInteractor by
            keyguardInteractor = keyguardInteractor,
            powerInteractor = powerInteractor,
            keyguardOcclusionInteractor = keyguardOcclusionInteractor,
            selectedUserInteractor = selectedUserInteractor,
            lockPatternUtils = lockPatternUtils,
        )
    }