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

Commit 30cea5fc authored by Hao Dong's avatar Hao Dong
Browse files

Do not ignore lockout error from face if it's class3.

Test: atest AuthBiometricFingerprintAndFaceViewTest
Bug: 277261318
Change-Id: Ibe971762f0dba4eabbd1b0f566e7df8e19b4422d
parent ef0421cf
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1970,8 +1970,8 @@
    <string name="face_error_user_canceled">Face Unlock canceled by user</string>
    <!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
    <string name="face_error_lockout">Too many attempts. Try again later.</string>
    <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
    <string name="face_error_lockout_permanent">Too many attempts. Face Unlock disabled.</string>
    <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=100] -->
    <string name="face_error_lockout_permanent">Too many attempts. Face Unlock unavailable.</string>
    <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
    <string name="face_error_lockout_screen_lock">Too many attempts. Enter screen lock instead.</string>
    <!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
+16 −1
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.systemui.biometrics
import android.content.Context
import android.hardware.biometrics.BiometricAuthenticator.Modality
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
import android.hardware.biometrics.BiometricConstants
import android.hardware.face.FaceManager
import android.util.AttributeSet
import com.android.systemui.R

@@ -27,6 +29,7 @@ class AuthBiometricFingerprintAndFaceView(
    context: Context,
    attrs: AttributeSet?
) : AuthBiometricFingerprintView(context, attrs) {
    var isFaceClass3 = false

    constructor (context: Context) : this(context, null)

@@ -34,10 +37,22 @@ class AuthBiometricFingerprintAndFaceView(

    override fun forceRequireConfirmation(@Modality modality: Int) = modality == TYPE_FACE

    override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int) = modality == TYPE_FACE
    override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int, unsuccessfulReason: String) =
        modality == TYPE_FACE && !(isFaceClass3 && isLockoutErrorString(unsuccessfulReason))

    override fun onPointerDown(failedModalities: Set<Int>) = failedModalities.contains(TYPE_FACE)

    override fun createIconController(): AuthIconController =
        AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)

    private fun isLockoutErrorString(unsuccessfulReason: String) =
        unsuccessfulReason == FaceManager.getErrorString(
            mContext,
            BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
            0 /*vendorCode */
        ) || unsuccessfulReason == FaceManager.getErrorString(
            mContext,
            BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
            0 /*vendorCode */
        )
}
+5 −4
Original line number Diff line number Diff line
@@ -258,7 +258,8 @@ public abstract class AuthBiometricView extends LinearLayout {
    }

    /** Ignore all events from this (secondary) modality except successful authentication. */
    protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality) {
    protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality,
            String unsuccessfulReason) {
        return false;
    }

@@ -541,7 +542,7 @@ public abstract class AuthBiometricView extends LinearLayout {
     */
    public void onAuthenticationFailed(
            @Modality int modality, @Nullable String failureReason) {
        if (ignoreUnsuccessfulEventsFrom(modality)) {
        if (ignoreUnsuccessfulEventsFrom(modality, failureReason)) {
            return;
        }

@@ -556,7 +557,7 @@ public abstract class AuthBiometricView extends LinearLayout {
     * @param error message
     */
    public void onError(@Modality int modality, String error) {
        if (ignoreUnsuccessfulEventsFrom(modality)) {
        if (ignoreUnsuccessfulEventsFrom(modality, error)) {
            return;
        }

@@ -586,7 +587,7 @@ public abstract class AuthBiometricView extends LinearLayout {
     * @param help message
     */
    public void onHelp(@Modality int modality, String help) {
        if (ignoreUnsuccessfulEventsFrom(modality)) {
        if (ignoreUnsuccessfulEventsFrom(modality, help)) {
            return;
        }
        if (mSize != AuthDialog.SIZE_MEDIUM) {
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.biometrics;

import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;

import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;

@@ -383,6 +384,8 @@ public class AuthContainerView extends LinearLayout
                fingerprintAndFaceView.setSensorProperties(fpProperties);
                fingerprintAndFaceView.setScaleFactorProvider(config.mScaleProvider);
                fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
                fingerprintAndFaceView.setFaceClass3(
                        faceProperties.sensorStrength == STRENGTH_STRONG);
                mBiometricView = fingerprintAndFaceView;
            } else if (fpProperties != null) {
                final AuthBiometricFingerprintView fpView =
+46 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.biometrics

import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
import android.hardware.biometrics.BiometricConstants
import android.hardware.face.FaceManager
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.view.View
@@ -34,6 +36,7 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.times
import org.mockito.junit.MockitoJUnit


@@ -98,7 +101,7 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
    }

    @Test
    fun ignoresFaceErrors() {
    fun ignoresFaceErrors_faceIsNotClass3_notLockoutError() {
        biometricView.onDialogAnimatedIn()
        biometricView.onError(TYPE_FACE, "not a face")
        waitForIdleSync()
@@ -113,5 +116,47 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
        verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
    }

    @Test
    fun doNotIgnoresFaceErrors_faceIsClass3_notLockoutError() {
        biometricView.isFaceClass3 = true
        biometricView.onDialogAnimatedIn()
        biometricView.onError(TYPE_FACE, "not a face")
        waitForIdleSync()

        assertThat(biometricView.isAuthenticating).isTrue()
        verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)

        biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
        TestableLooper.get(this).moveTimeForward(1000)
        waitForIdleSync()

        verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
    }

    @Test
    fun doNotIgnoresFaceErrors_faceIsClass3_lockoutError() {
        biometricView.isFaceClass3 = true
        biometricView.onDialogAnimatedIn()
        biometricView.onError(
            TYPE_FACE,
            FaceManager.getErrorString(
                biometricView.context,
                BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
                0 /*vendorCode */
            )
        )
        waitForIdleSync()

        assertThat(biometricView.isAuthenticating).isTrue()
        verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)

        biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
        TestableLooper.get(this).moveTimeForward(1000)
        waitForIdleSync()

        verify(callback, times(2)).onAction(AuthBiometricView.Callback.ACTION_ERROR)
    }


    override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
}