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

Commit 1a14e406 authored by Chandru S's avatar Chandru S Committed by Android (Google) Code Review
Browse files

Merge "skip processing onAuthenticationFailed if onAuthenticationError was...

Merge "skip processing onAuthenticationFailed if onAuthenticationError was already invoked for face lockout error" into main
parents 346ede2f 69fcc66b
Loading
Loading
Loading
Loading
+18 −14
Original line number Diff line number Diff line
@@ -56,6 +56,10 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
import com.google.errorprone.annotations.CompileTimeConstant
import java.io.PrintWriter
import java.util.Arrays
import java.util.stream.Collectors
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -78,10 +82,6 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.PrintWriter
import java.util.Arrays
import java.util.stream.Collectors
import javax.inject.Inject

/**
 * API to run face authentication and detection for device entry / on keyguard (as opposed to the
@@ -370,8 +370,10 @@ constructor(
                and(
                        displayStateInteractor.isDefaultDisplayOff,
                        keyguardTransitionInteractor.isFinishedInStateWhere(
                            KeyguardState::deviceIsAwakeInState),
                ).isFalse(),
                            KeyguardState::deviceIsAwakeInState
                        ),
                    )
                    .isFalse(),
                // this can happen if an app is requesting for screen off, the display can
                // turn off without wakefulness.isStartingToSleepOrAsleep calls
                "displayIsNotOffWhileFullyTransitionedToAwake",
@@ -381,10 +383,7 @@ constructor(
                "isFaceAuthEnrolledAndEnabled"
            ),
            Pair(keyguardRepository.isKeyguardGoingAway.isFalse(), "keyguardNotGoingAway"),
            Pair(
                powerInteractor.isAsleep.isFalse(),
                "deviceNotAsleep"
            ),
            Pair(powerInteractor.isAsleep.isFalse(), "deviceNotAsleep"),
            Pair(
                keyguardInteractor.isSecureCameraActive
                    .isFalse()
@@ -430,11 +429,16 @@ constructor(
    private val faceAuthCallback =
        object : FaceManager.AuthenticationCallback() {
            override fun onAuthenticationFailed() {
                _authenticationStatus.value = FailedFaceAuthenticationStatus()
                _isAuthenticated.value = false
                faceAuthLogger.authenticationFailed()
                if (!_isLockedOut.value) {
                    // onAuthenticationError gets invoked before onAuthenticationFailed when the
                    // last auth attempt locks out face authentication.
                    // Skip updating the authentication status in such a scenario.
                    _authenticationStatus.value = FailedFaceAuthenticationStatus()
                    onFaceAuthRequestCompleted()
                }
            }

            override fun onAuthenticationAcquired(acquireInfo: Int) {
                _authenticationStatus.value = AcquiredFaceAuthenticationStatus(acquireInfo)
+52 −26
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMET
import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED
import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
@@ -82,6 +81,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.FakeKeyguardStateController
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.user.data.model.SelectionStatus
@@ -94,6 +94,8 @@ import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.time.SystemClock
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
@@ -116,8 +118,6 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
import java.io.PrintWriter
import java.io.StringWriter

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -195,9 +195,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
            }

        powerRepository = FakePowerRepository()
        powerInteractor = PowerInteractorFactory.create(
        powerInteractor =
            PowerInteractorFactory.create(
                    repository = powerRepository,
        ).powerInteractor
                )
                .powerInteractor

        val withDeps =
            KeyguardInteractorFactory.create(
@@ -635,11 +637,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {

    @Test
    fun authenticateDoesNotRunWhenDeviceIsGoingToSleep() =
        testScope.runTest {
            testGatingCheckForFaceAuth {
                powerInteractor.setAsleepForTest()
            }
        }
        testScope.runTest { testGatingCheckForFaceAuth { powerInteractor.setAsleepForTest() } }

    @Test
    fun authenticateDoesNotRunWhenSecureCameraIsActive() =
@@ -736,17 +734,21 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
            allPreconditionsToRunFaceAuthAreTrue()

            Log.i("TEST", "started waking")
            keyguardTransitionRepository.sendTransitionStep(TransitionStep(
            keyguardTransitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.LOCKSCREEN,
                    to = KeyguardState.OFF,
                    transitionState = TransitionState.FINISHED,
            ))
                )
            )
            runCurrent()
            keyguardTransitionRepository.sendTransitionStep(TransitionStep(
            keyguardTransitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.OFF,
                    to = KeyguardState.LOCKSCREEN,
                    transitionState = TransitionState.STARTED,
            ))
                )
            )
            runCurrent()

            Log.i("TEST", "sending display off")
@@ -766,11 +768,13 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
        testScope.runTest {
            testGatingCheckForFaceAuth {
                powerInteractor.onFinishedWakingUp()
                keyguardTransitionRepository.sendTransitionStep(TransitionStep(
                keyguardTransitionRepository.sendTransitionStep(
                    TransitionStep(
                        from = KeyguardState.OFF,
                        to = KeyguardState.LOCKSCREEN,
                        transitionState = TransitionState.FINISHED,
                ))
                    )
                )
                runCurrent()

                displayRepository.emit(
@@ -919,11 +923,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {

    @Test
    fun detectDoesNotRunWhenDeviceSleepingStartingToSleep() =
        testScope.runTest {
            testGatingCheckForDetect {
                powerInteractor.setAsleepForTest()
            }
        }
        testScope.runTest { testGatingCheckForDetect { powerInteractor.setAsleepForTest() } }

    @Test
    fun detectDoesNotRunWhenSecureCameraIsActive() =
@@ -1114,6 +1114,32 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
            biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
            faceAuthenticateIsCalled()
        }
    @Test
    fun authFailedCallAfterAuthLockedOutErrorShouldBeIgnored() =
        testScope.runTest {
            initCollectors()
            allPreconditionsToRunFaceAuthAreTrue()
            runCurrent()
            assertThat(canFaceAuthRun()).isTrue()

            underTest.requestAuthenticate(FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED, false)
            runCurrent()

            faceAuthenticateIsCalled()
            authenticationCallback.value.onAuthenticationError(
                FACE_ERROR_LOCKOUT_PERMANENT,
                "Too many attempts, face not available"
            )

            val lockoutError = authStatus() as ErrorFaceAuthenticationStatus
            assertThat(lockedOut()).isTrue()
            assertThat(lockoutError.isLockoutError()).isTrue()

            authenticationCallback.value.onAuthenticationFailed()
            runCurrent()

            assertThat(authStatus()).isEqualTo(lockoutError)
        }

    private suspend fun TestScope.testGatingCheckForFaceAuth(
        gatingCheckModifier: suspend () -> Unit