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

Commit 4d6586a5 authored by Beverly's avatar Beverly Committed by Automerger Merge Worker
Browse files

RESTRICT AUTOMERGE Fix detect biometric logic. am: 5cfa9271

parents 2625e6e4 5cfa9271
Loading
Loading
Loading
Loading
+51 −12
Original line number Diff line number Diff line
@@ -814,6 +814,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }
    }

    private void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
            boolean isStrongBiometric) {
        Assert.isMainThread();
        Trace.beginSection("KeyGuardUpdateMonitor#onBiometricDetected");
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
                cb.onBiometricDetected(userId, biometricSourceType, isStrongBiometric);
            }
        }
        Trace.endSection();
    }

    @VisibleForTesting
    protected void onFingerprintAuthenticated(int userId, boolean isStrongBiometric) {
        Assert.isMainThread();
@@ -890,6 +903,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }
    }

    private void handleBiometricDetected(int authUserId, BiometricSourceType biometricSourceType,
            boolean isStrongBiometric) {
        Trace.beginSection("KeyGuardUpdateMonitor#handlerBiometricDetected");
        onBiometricDetected(authUserId, biometricSourceType, isStrongBiometric);
        if (biometricSourceType == FINGERPRINT) {
            mLogger.logFingerprintDetected(authUserId, isStrongBiometric);
        } else if (biometricSourceType == FACE) {
            mLogger.logFaceDetected(authUserId, isStrongBiometric);
            setFaceRunningState(BIOMETRIC_STATE_STOPPED);
        }

        Trace.endSection();
    }

    private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) {
        Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
        if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
@@ -941,9 +968,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab

    private void onFingerprintCancelNotReceived() {
        mLogger.e("Fp cancellation not received, transitioning to STOPPED");
        final boolean wasCancellingRestarting = mFingerprintRunningState
                == BIOMETRIC_STATE_CANCELLING_RESTARTING;
        mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
        if (wasCancellingRestarting) {
            KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
        } else {
            KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
        }
    }

    private void handleFingerprintError(int msgId, String errString) {
        Assert.isMainThread();
@@ -1029,6 +1062,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                    () -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE),
                    getBiometricLockoutDelay());
        } else {
            boolean temporaryLockoutReset = wasLockout && !mFingerprintLockedOut;
            if (temporaryLockoutReset) {
                mLogger.d("temporaryLockoutReset - stopListeningForFingerprint() to stop"
                        + " detectFingerprint");
                stopListeningForFingerprint();
            }
            updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
        }

@@ -1728,10 +1767,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                }
            };

    private final FingerprintManager.FingerprintDetectionCallback mFingerprintDetectionCallback =
            (sensorId, userId, isStrongBiometric) -> {
                // Trigger the fingerprint detected path so the bouncer can be shown
                handleBiometricDetected(userId, FINGERPRINT, isStrongBiometric);
            };

    private final FaceManager.FaceDetectionCallback mFaceDetectionCallback
            = (sensorId, userId, isStrongBiometric) -> {
                // Trigger the face success path so the bouncer can be shown
                handleFaceAuthenticated(userId, isStrongBiometric);
                // Trigger the face detected path so the bouncer can be shown
                handleBiometricDetected(userId, FACE, isStrongBiometric);
            };

    @VisibleForTesting
@@ -2759,8 +2804,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab

        boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
                && shouldListenBouncerState && shouldListenUdfpsState
                && shouldListenSideFpsState
                && !isFingerprintLockedOut();
                && shouldListenSideFpsState;
        logListenerModelData(
                new KeyguardFingerprintListenModel(
                    System.currentTimeMillis(),
@@ -2819,8 +2863,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        final boolean supportsDetect = !mFaceSensorProperties.isEmpty()
                && mFaceSensorProperties.get(0).supportsFaceDetection
                && canBypass && !mPrimaryBouncerIsOrWillBeShowing
                && !isUserInLockdown(user)
                && !isFingerprintLockedOut();
                && !isUserInLockdown(user);
        final boolean faceAuthAllowedOrDetectionIsNeeded = faceAuthAllowed || supportsDetect;

        // If the face or fp has recently been authenticated do not attempt to authenticate again.
@@ -2916,11 +2959,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                mLogger.v("startListeningForFingerprint - detect");
                mFpm.detectFingerprint(
                        mFingerprintCancelSignal,
                        (sensorId, user, isStrongBiometric) -> {
                            mLogger.d("fingerprint detected");
                            // Trigger the fingerprint success path so the bouncer can be shown
                            handleFingerprintAuthenticated(user, isStrongBiometric);
                        },
                        mFingerprintDetectionCallback,
                        userId);
            } else {
                mLogger.v("startListeningForFingerprint - authenticate");
+9 −1
Original line number Diff line number Diff line
@@ -214,13 +214,21 @@ public class KeyguardUpdateMonitorCallback {
    public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) { }

    /**
     * Called when a biometric is recognized.
     * Called when a biometric is authenticated.
     * @param userId the user id for which the biometric sample was authenticated
     * @param biometricSourceType
     */
    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
            boolean isStrongBiometric) { }

    /**
     * Called when a biometric is detected but not successfully authenticated.
     * @param userId the user id for which the biometric sample was detected
     * @param biometricSourceType
     */
    public void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
            boolean isStrongBiometric) { }

    /**
     * Called when biometric authentication provides help string (e.g. "Try again")
     * @param msgId
+14 −0
Original line number Diff line number Diff line
@@ -167,6 +167,20 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
        }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
    }

    fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) {
        logBuffer.log(TAG, DEBUG, {
            int1 = userId
            bool1 = isStrongBiometric
        }, {"Face detected: userId: $int1, isStrongBiometric: $bool1"})
    }

    fun logFingerprintDetected(userId: Int, isStrongBiometric: Boolean) {
        logBuffer.log(TAG, DEBUG, {
            int1 = userId
            bool1 = isStrongBiometric
        }, {"Fingerprint detected: userId: $int1, isStrongBiometric: $bool1"})
    }

    fun logFingerprintError(msgId: Int, originalErrMsg: String) {
        logBuffer.log(TAG, DEBUG, {
            str1 = originalErrMsg
+11 −0
Original line number Diff line number Diff line
@@ -382,6 +382,17 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
        Trace.endSection();
    }

    @Override
    public void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
            boolean isStrongBiometric) {
        Trace.beginSection("BiometricUnlockController#onBiometricDetected");
        if (mUpdateMonitor.isGoingToSleep()) {
            Trace.endSection();
            return;
        }
        startWakeAndUnlock(MODE_SHOW_BOUNCER);
    }

    @Override
    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
            boolean isStrongBiometric) {
+91 −65
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING;
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
@@ -614,19 +613,47 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {

    @Test
    public void testOnlyDetectFingerprint_whenFingerprintUnlockNotAllowed() {
        // Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
        // will trigger updateBiometricListeningState();
        clearInvocations(mFingerprintManager);
        mKeyguardUpdateMonitor.resetBiometricListeningState();

        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
        mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
        mTestableLooper.processAllMessages();
        givenDetectFingerprintWithClearingFingerprintManagerInvocations();

        verifyFingerprintAuthenticateNeverCalled();
        verifyFingerprintDetectCall();
    }

    @Test
    public void whenDetectFingerprint_biometricDetectCallback() {
        ArgumentCaptor<FingerprintManager.FingerprintDetectionCallback> fpDetectCallbackCaptor =
                ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class);

        givenDetectFingerprintWithClearingFingerprintManagerInvocations();
        verify(mFingerprintManager).detectFingerprint(
                any(), fpDetectCallbackCaptor.capture(), anyInt());
        fpDetectCallbackCaptor.getValue().onFingerprintDetected(0, 0, true);

        // THEN verify keyguardUpdateMonitorCallback receives a detect callback
        // and NO authenticate callbacks
        verify(mTestCallback).onBiometricDetected(
                eq(0), eq(BiometricSourceType.FINGERPRINT), eq(true));
        verify(mTestCallback, never()).onBiometricAuthenticated(
                anyInt(), any(), anyBoolean());
    }

    @Test
    public void whenDetectFace_biometricDetectCallback() {
        ArgumentCaptor<FaceManager.FaceDetectionCallback> faceDetectCallbackCaptor =
                ArgumentCaptor.forClass(FaceManager.FaceDetectionCallback.class);

        givenDetectFace();
        verify(mFaceManager).detectFace(any(), faceDetectCallbackCaptor.capture(), anyInt());
        faceDetectCallbackCaptor.getValue().onFaceDetected(0, 0, false);

        // THEN verify keyguardUpdateMonitorCallback receives a detect callback
        // and NO authenticate callbacks
        verify(mTestCallback).onBiometricDetected(
                eq(0), eq(BiometricSourceType.FACE), eq(false));
        verify(mTestCallback, never()).onBiometricAuthenticated(
                anyInt(), any(), anyBoolean());
    }

    @Test
    public void testUnlockingWithFaceAllowed_strongAuthTrackerUnlockingWithBiometricAllowed() {
        // GIVEN unlocking with biometric is allowed
@@ -655,7 +682,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        strongAuthNotRequired();

        // WHEN fingerprint is locked out
        fingerprintErrorLockedOut();
        fingerprintErrorTemporaryLockedOut();

        // THEN unlocking with face is not allowed
        Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
@@ -678,7 +705,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        strongAuthNotRequired();

        // WHEN fingerprint is locked out
        fingerprintErrorLockedOut();
        fingerprintErrorTemporaryLockedOut();

        // THEN unlocking with fingerprint is not allowed
        Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
@@ -702,7 +729,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));

        // WHEN fingerprint is locked out
        fingerprintErrorLockedOut();
        fingerprintErrorTemporaryLockedOut();

        // THEN user is NOT considered as "having trust" and bouncer cannot be skipped
        Assert.assertFalse(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
@@ -764,11 +791,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {

    @Test
    public void nofaceDetect_whenStrongAuthRequiredAndBypassUdfpsSupportedAndFpRunning() {
        // GIVEN mocked keyguardUpdateMonitorCallback
        KeyguardUpdateMonitorCallback keyguardUpdateMonitorCallback =
                mock(KeyguardUpdateMonitorCallback.class);
        mKeyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback);

        // GIVEN bypass is enabled, face detection is supported
        lockscreenBypassIsAllowed();
        supportsFaceDetection();
@@ -787,22 +809,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        verifyFaceAuthenticateNeverCalled();

        // THEN biometric help message sent to callback
        verify(keyguardUpdateMonitorCallback).onBiometricHelp(
        verify(mTestCallback).onBiometricHelp(
                eq(BIOMETRIC_HELP_FACE_NOT_AVAILABLE), anyString(), eq(BiometricSourceType.FACE));
    }

    @Test
    public void faceDetect_whenStrongAuthRequiredAndBypass() {
        // GIVEN bypass is enabled, face detection is supported and strong auth is required
        lockscreenBypassIsAllowed();
        supportsFaceDetection();
        strongAuthRequiredEncrypted();
        keyguardIsVisible();
        // fingerprint is NOT running, UDFPS is NOT supported

        // WHEN the device wakes up
        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
        mTestableLooper.processAllMessages();
        givenDetectFace();

        // FACE detect is triggered, not authenticate
        verifyFaceDetectCall();
@@ -818,39 +831,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        verifyFaceDetectNeverCalled();
    }

    @Test
    public void noFaceRun_whenFpLockout() {
        // GIVEN bypass is enabled, face detection is supported and strong auth is required
        lockscreenBypassIsAllowed();
        supportsFaceDetection();
        strongAuthRequiredEncrypted();
        keyguardIsVisible();
        // fingerprint is NOT running, UDFPS is NOT supported

        // GIVEN fp is locked out
        when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), anyInt()))
                .thenReturn(BIOMETRIC_LOCKOUT_TIMED);
        mKeyguardUpdateMonitor.handleUserSwitchComplete(0);
        assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(true);

        // WHEN the device wakes up
        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
        mTestableLooper.processAllMessages();

        // FACE detect is NOT triggered and face authenticate is NOT triggered
        verifyFaceDetectNeverCalled();
        verifyFaceAuthenticateNeverCalled();

        // WHEN bouncer becomes visible
        setKeyguardBouncerVisibility(true);
        clearInvocations(mFaceManager);

        // THEN face scanning is not run
        mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
        verifyFaceAuthenticateNeverCalled();
        verifyFaceDetectNeverCalled();
    }

    @Test
    public void noFaceDetect_whenStrongAuthRequiredAndBypass_faceDetectionUnsupported() {
        // GIVEN bypass is enabled, face detection is NOT supported and strong auth is required
@@ -1159,8 +1139,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        // Fingerprint should be cancelled on lockout if going to lockout state, else
        // restarted if it's not
        assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState)
                .isEqualTo(fpLocked
                        ? BIOMETRIC_STATE_CANCELLING : BIOMETRIC_STATE_CANCELLING_RESTARTING);
                .isEqualTo(BIOMETRIC_STATE_CANCELLING_RESTARTING);
    }

    @Test
@@ -1619,7 +1598,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();

        // Fingerprint is locked out.
        fingerprintErrorLockedOut();
        fingerprintErrorTemporaryLockedOut();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }
@@ -2428,6 +2407,29 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
                eq(false));
    }

    @Test
    public void detectFingerprint_onTemporaryLockoutReset_authenticateFingerprint() {
        ArgumentCaptor<FingerprintManager.LockoutResetCallback> fpLockoutResetCallbackCaptor =
                ArgumentCaptor.forClass(FingerprintManager.LockoutResetCallback.class);
        verify(mFingerprintManager).addLockoutResetCallback(fpLockoutResetCallbackCaptor.capture());

        // GIVEN device is locked out
        fingerprintErrorTemporaryLockedOut();

        // GIVEN FP detection is running
        givenDetectFingerprintWithClearingFingerprintManagerInvocations();
        verifyFingerprintDetectCall();
        verifyFingerprintAuthenticateNeverCalled();

        // WHEN temporary lockout resets
        fpLockoutResetCallbackCaptor.getValue().onLockoutReset(0);
        mTestableLooper.processAllMessages();

        // THEN fingerprint detect state should cancel & then restart (for authenticate call)
        assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState)
                .isEqualTo(BIOMETRIC_STATE_CANCELLING_RESTARTING);
    }

    private void verifyFingerprintAuthenticateNeverCalled() {
        verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
                anyInt(), anyInt());
@@ -2532,7 +2534,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        mKeyguardUpdateMonitor.setSwitchingUser(true);
    }

    private void fingerprintErrorLockedOut() {
    private void fingerprintErrorTemporaryLockedOut() {
        mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
                .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
    }
@@ -2672,6 +2674,30 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        receiver.setPendingResult(pendingResult);
    }

    private void givenDetectFingerprintWithClearingFingerprintManagerInvocations() {
        // Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
        // will trigger updateBiometricListeningState();
        clearInvocations(mFingerprintManager);
        mKeyguardUpdateMonitor.resetBiometricListeningState();

        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
        mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
        mTestableLooper.processAllMessages();
    }

    private void givenDetectFace() {
        // GIVEN bypass is enabled, face detection is supported and strong auth is required
        lockscreenBypassIsAllowed();
        supportsFaceDetection();
        strongAuthRequiredEncrypted();
        keyguardIsVisible();
        // fingerprint is NOT running, UDFPS is NOT supported

        // WHEN the device wakes up
        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
        mTestableLooper.processAllMessages();
    }

    private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
        int subscription = simInited
                ? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;
Loading