From 11ff6387d5a780d32ad54543779dc351e019ca48 Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 16 Feb 2023 19:21:17 +0000 Subject: [PATCH] Fix detect biometric logic. Reverts the revert: Iea66d7782b3365dea827b854783aeddaa5c6699c and updates the detect biometric logic to forward fix the CUJ. [1] Never allow detectFingerprint or detectFace to enter the device. DetectBiometric at most can bring up the bouncer. It will never run the authenticate path. [2] When the temporary lockout state is reset, reset the fingerprint listening state so that if SysUI was running detection, SysUI will subsequently switch over to running authenticate. If there's faceDetect running when lockout resets, we allow faceDetect to complete running - if successful, it'll bring up the bouncer where the user can either enter pin/pattern/password to enter the device, or attempt face auth again by tapping the bouncer. [3] Not directly related to detect but was causing a stuck BIOMETRIC_CANCELLING_RESTARTING state: make sure to update the biometric running state if the cancellation signal times out and the biometric running state was BIOMETRIC_CANCELLING_RESTARTING. Previously, the biometric state was only STOPPED when the cancellation signal (framework didn't get back to SysUI in time) timed out Note: There's a bug b/269743883 in the detect CUJ where if its requested right after being cancelled, it can be stuck in the CANCELLING_RESTARTING state. However, this will timeout after 3000ms and restart the fingerprint listening state afterwards. This will be an issue until the framework bug is resolved to send the cancellation confirmation to SysUI. Test: atest KeyguardUpdateMonitorTest BiometricsUnlockControllerTest Test: after the lockout, putting any finger on the FP sensor will bring up the bouncer. after the lockout counter expires, putting an unenrolled finger on the FP sensor will result in a FP error. only enrolled fingerprints will allow the user to enter the device. Bug: 269574598 Bug: 269769293 Bug: 269200614 Change-Id: Ic8f3d5b8b6a898a6d22f69c6e2ed4a3c24c61a6b --- .../keyguard/KeyguardUpdateMonitor.java | 65 ++++++-- .../KeyguardUpdateMonitorCallback.java | 10 +- .../logging/KeyguardUpdateMonitorLogger.kt | 14 ++ .../phone/BiometricUnlockController.java | 11 ++ .../keyguard/KeyguardUpdateMonitorTest.java | 157 ++++++++++-------- .../phone/BiometricsUnlockControllerTest.java | 20 +++ .../fingerprint/FingerprintService.java | 7 - 7 files changed, 197 insertions(+), 87 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index bd67115e51175..4d7a76f1f4d2a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -139,9 +139,9 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; +import com.android.settingslib.Utils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; -import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; @@ -823,6 +823,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(); @@ -899,6 +912,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)) { @@ -950,8 +977,14 @@ 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; - KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_STOP); + if (wasCancellingRestarting) { + KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); + } else { + KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_STOP); + } } private void handleFingerprintError(int msgId, String errString) { @@ -1038,6 +1071,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); } @@ -1747,10 +1786,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 @@ -2783,8 +2828,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab boolean shouldListen = shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState && shouldListenUdfpsState - && shouldListenSideFpsState - && !isFingerprintLockedOut(); + && shouldListenSideFpsState; logListenerModelData( new KeyguardFingerprintListenModel( System.currentTimeMillis(), @@ -2843,8 +2887,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. @@ -2940,11 +2983,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, new FingerprintAuthenticateOptions.Builder() .setUserId(userId) .build()); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 38f3e5065eec0..0d4889a4c39f3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -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 diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index c414c088529cd..e53f6adb62a49 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 9f3836105a958..7855cdfeb4c33 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -373,6 +373,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) { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 09b738fd26db8..074c27c80e905 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -18,7 +18,6 @@ package com.android.keyguard; import static android.app.StatusBarManager.SESSION_KEYGUARD; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; -import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON; @@ -30,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; @@ -633,19 +631,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 fpDetectCallbackCaptor = + ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class); + + givenDetectFingerprintWithClearingFingerprintManagerInvocations(); + verify(mFingerprintManager).detectFingerprint( + any(), fpDetectCallbackCaptor.capture(), any()); + 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 faceDetectCallbackCaptor = + ArgumentCaptor.forClass(FaceManager.FaceDetectionCallback.class); + + givenDetectFace(); + verify(mFaceManager).detectFace(any(), faceDetectCallbackCaptor.capture(), any()); + 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 @@ -674,7 +700,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( @@ -697,7 +723,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( @@ -721,7 +747,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())); @@ -781,11 +807,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(); @@ -804,22 +825,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(); @@ -835,39 +847,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 @@ -1186,8 +1165,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 @@ -1646,7 +1624,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue(); // Fingerprint is locked out. - fingerprintErrorLockedOut(); + fingerprintErrorTemporaryLockedOut(); assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse(); } @@ -2499,6 +2477,29 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { eq(false)); } + @Test + public void detectFingerprint_onTemporaryLockoutReset_authenticateFingerprint() { + ArgumentCaptor 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()); @@ -2602,7 +2603,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.setSwitchingUser(true); } - private void fingerprintErrorLockedOut() { + private void fingerprintErrorTemporaryLockedOut() { mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out"); } @@ -2741,6 +2742,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; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index ec294b12a11a7..68d67ca200070 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -517,6 +517,26 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { verify(mVibratorHelper).vibrateAuthError(anyString()); } + @Test + public void onFingerprintDetect_showBouncer() { + // WHEN fingerprint detect occurs + mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT, + BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */); + + // THEN shows primary bouncer + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean()); + } + + @Test + public void onFaceDetect_showBouncer() { + // WHEN face detect occurs + mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT, + BiometricSourceType.FACE, false /* isStrongBiometric */); + + // THEN shows primary bouncer + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean()); + } + private void givenFingerprintModeUnlockCollapsing() { when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 8a33f22d69673..f6c1375730bb4 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -427,13 +427,6 @@ public class FingerprintService extends SystemService { return -1; } - if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, options.getUserId())) { - // If this happens, something in KeyguardUpdateMonitor is wrong. This should only - // ever be invoked when the user is encrypted or lockdown. - Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown"); - return -1; - } - final Pair provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for detectFingerprint");