Loading core/java/android/hardware/biometrics/BiometricConstants.java +23 −0 Original line number Diff line number Diff line Loading @@ -268,4 +268,27 @@ public interface BiometricConstants { */ int BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL = 1; /** * No lockout. * @hide */ int BIOMETRIC_LOCKOUT_NONE = 0; /** * The biometric is in a temporary lockout state that will expire after some time. * @hide */ int BIOMETRIC_LOCKOUT_TIMED = 1; /** * The biometric is locked out until a reset occurs. Resets are typically triggered by * successfully authenticating via a stronger method than the one that is locked out. * @hide */ int BIOMETRIC_LOCKOUT_PERMANENT = 2; /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({BIOMETRIC_LOCKOUT_NONE, BIOMETRIC_LOCKOUT_TIMED, BIOMETRIC_LOCKOUT_PERMANENT}) @interface LockoutMode {} } core/java/android/hardware/face/FaceManager.java +17 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.face; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -672,6 +673,22 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan return new ArrayList<>(); } /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @BiometricConstants.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) { if (mService != null) { try { return mService.getLockoutModeForUser(sensorId, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } return BIOMETRIC_LOCKOUT_NONE; } /** * @hide */ Loading core/java/android/hardware/fingerprint/FingerprintManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.Manifest.permission.TEST_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.Manifest.permission.USE_FINGERPRINT; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON; import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE; Loading @@ -41,6 +42,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricTestSession; Loading Loading @@ -1094,6 +1096,22 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @BiometricConstants.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) { if (mService != null) { try { return mService.getLockoutModeForUser(sensorId, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } return BIOMETRIC_LOCKOUT_NONE; } /** * @hide */ Loading packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +45 −16 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.ACTION_USER_STOPPED; import static android.content.Intent.ACTION_USER_UNLOCKED; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED; import static android.hardware.biometrics.BiometricConstants.LockoutMode; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; Loading Loading @@ -61,6 +65,7 @@ import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.nfc.NfcAdapter; import android.os.Build; import android.os.CancellationSignal; Loading Loading @@ -865,10 +870,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } private void handleFingerprintLockoutReset() { boolean changed = mFingerprintLockedOut || mFingerprintLockedOutPermanent; mFingerprintLockedOut = false; mFingerprintLockedOutPermanent = false; private void handleFingerprintLockoutReset(@LockoutMode int mode) { Log.d(TAG, "handleFingerprintLockoutReset: " + mode); final boolean wasLockout = mFingerprintLockedOut; final boolean wasLockoutPermanent = mFingerprintLockedOutPermanent; mFingerprintLockedOut = (mode == BIOMETRIC_LOCKOUT_TIMED) || mode == BIOMETRIC_LOCKOUT_PERMANENT; mFingerprintLockedOutPermanent = (mode == BIOMETRIC_LOCKOUT_PERMANENT); final boolean changed = (mFingerprintLockedOut != wasLockout) || (mFingerprintLockedOutPermanent != wasLockoutPermanent); if (isUdfpsEnrolled()) { // TODO(b/194825098): update the reset signal(s) Loading @@ -878,7 +888,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // be noticeable. mHandler.postDelayed(() -> { updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS); }, getBiometricLockoutDelay()); } else { updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); } Loading Loading @@ -1076,13 +1086,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } private void handleFaceLockoutReset() { boolean changed = mFaceLockedOutPermanent; mFaceLockedOutPermanent = false; private void handleFaceLockoutReset(@LockoutMode int mode) { Log.d(TAG, "handleFaceLockoutReset: " + mode); final boolean wasLockoutPermanent = mFaceLockedOutPermanent; mFaceLockedOutPermanent = (mode == BIOMETRIC_LOCKOUT_PERMANENT); final boolean changed = (mFaceLockedOutPermanent != wasLockoutPermanent); mHandler.postDelayed(() -> { updateFaceListeningState(BIOMETRIC_ACTION_UPDATE); }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS); }, getBiometricLockoutDelay()); if (changed) { notifyLockedOutStateChanged(BiometricSourceType.FACE); Loading Loading @@ -1462,7 +1474,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab = new FingerprintManager.LockoutResetCallback() { @Override public void onLockoutReset(int sensorId) { handleFingerprintLockoutReset(); handleFingerprintLockoutReset(BIOMETRIC_LOCKOUT_NONE); } }; Loading @@ -1470,7 +1482,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab = new FaceManager.LockoutResetCallback() { @Override public void onLockoutReset(int sensorId) { handleFaceLockoutReset(); handleFaceLockoutReset(BIOMETRIC_LOCKOUT_NONE); } }; Loading Loading @@ -1580,10 +1592,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }; private CancellationSignal mFingerprintCancelSignal; private CancellationSignal mFaceCancelSignal; @VisibleForTesting CancellationSignal mFingerprintCancelSignal; @VisibleForTesting CancellationSignal mFaceCancelSignal; private FingerprintManager mFpm; private FaceManager mFaceManager; private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; private List<FaceSensorPropertiesInternal> mFaceSensorProperties; private boolean mFingerprintLockedOut; private boolean mFingerprintLockedOutPermanent; Loading Loading @@ -2018,6 +2033,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); mFingerprintSensorProperties = mFpm.getSensorPropertiesInternal(); } if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { mFaceManager = (FaceManager) context.getSystemService(Context.FACE_SERVICE); Loading Loading @@ -2382,11 +2398,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean shouldListenUdfpsState = !isUdfps || (!userCanSkipBouncer && !isEncryptedOrLockdownForUser && userDoesNotHaveTrust && !mFingerprintLockedOut); && userDoesNotHaveTrust); final boolean shouldListen = shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState && shouldListenUdfpsState; && shouldListenBouncerState && shouldListenUdfpsState && !isFingerprintLockedOut(); if (DEBUG_FINGERPRINT || DEBUG_SPEW) { maybeLogListenerModelData( Loading Loading @@ -2773,6 +2788,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onUserSwitchComplete(userId); } } if (mFaceManager != null && !mFaceSensorProperties.isEmpty()) { handleFaceLockoutReset(mFaceManager.getLockoutModeForUser( mFaceSensorProperties.get(0).sensorId, userId)); } if (mFpm != null && !mFingerprintSensorProperties.isEmpty()) { handleFingerprintLockoutReset(mFpm.getLockoutModeForUser( mFingerprintSensorProperties.get(0).sensorId, userId)); } mInteractionJankMonitor.end(InteractionJankMonitor.CUJ_USER_SWITCH); mLatencyTracker.onActionEnd(LatencyTracker.ACTION_USER_SWITCH); } Loading Loading @@ -3508,6 +3533,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } protected int getBiometricLockoutDelay() { return BIOMETRIC_LOCKOUT_RESET_DELAY_MS; } /** * Unregister all listeners. */ Loading packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +83 −1 Original line number Diff line number Diff line Loading @@ -35,10 +35,12 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; Loading @@ -50,15 +52,20 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorProperties; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.IRemoteCallback; import android.os.UserHandle; Loading Loading @@ -121,6 +128,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "", DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID, TEST_CARRIER_ID, 0); private static final int FACE_SENSOR_ID = 0; private static final int FINGERPRINT_SENSOR_ID = 1; @Mock private DumpManager mDumpManager; @Mock Loading Loading @@ -212,6 +222,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mFingerprintManager.isHardwareDetected()).thenReturn(true); when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(List.of( new FingerprintSensorPropertiesInternal(1 /* sensorId */, FingerprintSensorProperties.STRENGTH_STRONG, 1 /* maxEnrollmentsPerUser */, List.of(new ComponentInfoInternal("fingerprintSensor" /* componentId */, "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, "00000001" /* serialNumber */, "" /* softwareVersion */)), FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, false /* resetLockoutRequiresHAT */))); when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true); when(mUserManager.isPrimaryUser()).thenReturn(true); when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class)); Loading @@ -232,9 +252,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mSpiedContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); mMockitoSession = ExtendedMockito.mockitoSession() .spyStatic(SubscriptionManager.class).startMocking(); .spyStatic(SubscriptionManager.class) .spyStatic(ActivityManager.class) .startMocking(); ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(SubscriptionManager::getDefaultSubscriptionId); ExtendedMockito.doReturn(KeyguardUpdateMonitor.getCurrentUser()) .when(ActivityManager::getCurrentUser); mTestableLooper = TestableLooper.get(this); allowTestableLooperAsMainThread(); Loading Loading @@ -765,6 +789,59 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { verify(mLatencyTracker).onActionEnd(LatencyTracker.ACTION_USER_SWITCH); } @Test public void testMultiUserLockoutChanged_whenUserSwitches() { testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT, BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT); } @Test public void testMultiUserLockoutNotChanged_whenUserSwitches() { testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_NONE, BiometricConstants.BIOMETRIC_LOCKOUT_NONE); } private void testMultiUserLockout_whenUserSwitches( @BiometricConstants.LockoutMode int fingerprintLockoutMode, @BiometricConstants.LockoutMode int faceLockoutMode) { final int newUser = 12; final boolean faceLocked = faceLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE; final boolean fpLocked = fingerprintLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE; when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), eq(newUser))) .thenReturn(fingerprintLockoutMode); when(mFaceManager.getLockoutModeForUser(eq(FACE_SENSOR_ID), eq(newUser))) .thenReturn(faceLockoutMode); mKeyguardUpdateMonitor.dispatchStartedWakingUp(); mTestableLooper.processAllMessages(); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal); final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal); mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel; mKeyguardUpdateMonitor.mFingerprintCancelSignal = fpCancel; KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class); mKeyguardUpdateMonitor.registerCallback(callback); mKeyguardUpdateMonitor.handleUserSwitchComplete(newUser); mTestableLooper.processAllMessages(); verify(faceCancel, faceLocked ? times(1) : never()).cancel(); verify(fpCancel, fpLocked ? times(1) : never()).cancel(); verify(callback, faceLocked ? times(1) : never()).onBiometricRunningStateChanged( eq(false), eq(BiometricSourceType.FACE)); verify(callback, fpLocked ? times(1) : never()).onBiometricRunningStateChanged( eq(false), eq(BiometricSourceType.FINGERPRINT)); assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(fpLocked); assertThat(mKeyguardUpdateMonitor.isFaceLockedOut()).isEqualTo(faceLocked); } @Test public void testGetUserCanSkipBouncer_whenTrust() { int user = KeyguardUpdateMonitor.getCurrentUser(); Loading Loading @@ -1124,5 +1201,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mSimStateChanged.set(true); super.handleSimStateChange(subId, slotId, state); } @Override protected int getBiometricLockoutDelay() { return 0; } } } Loading
core/java/android/hardware/biometrics/BiometricConstants.java +23 −0 Original line number Diff line number Diff line Loading @@ -268,4 +268,27 @@ public interface BiometricConstants { */ int BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL = 1; /** * No lockout. * @hide */ int BIOMETRIC_LOCKOUT_NONE = 0; /** * The biometric is in a temporary lockout state that will expire after some time. * @hide */ int BIOMETRIC_LOCKOUT_TIMED = 1; /** * The biometric is locked out until a reset occurs. Resets are typically triggered by * successfully authenticating via a stronger method than the one that is locked out. * @hide */ int BIOMETRIC_LOCKOUT_PERMANENT = 2; /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({BIOMETRIC_LOCKOUT_NONE, BIOMETRIC_LOCKOUT_TIMED, BIOMETRIC_LOCKOUT_PERMANENT}) @interface LockoutMode {} }
core/java/android/hardware/face/FaceManager.java +17 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.face; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -672,6 +673,22 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan return new ArrayList<>(); } /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @BiometricConstants.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) { if (mService != null) { try { return mService.getLockoutModeForUser(sensorId, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } return BIOMETRIC_LOCKOUT_NONE; } /** * @hide */ Loading
core/java/android/hardware/fingerprint/FingerprintManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.Manifest.permission.TEST_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.Manifest.permission.USE_FINGERPRINT; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON; import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE; Loading @@ -41,6 +42,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricTestSession; Loading Loading @@ -1094,6 +1096,22 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @BiometricConstants.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) { if (mService != null) { try { return mService.getLockoutModeForUser(sensorId, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } return BIOMETRIC_LOCKOUT_NONE; } /** * @hide */ Loading
packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +45 −16 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.ACTION_USER_STOPPED; import static android.content.Intent.ACTION_USER_UNLOCKED; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED; import static android.hardware.biometrics.BiometricConstants.LockoutMode; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; Loading Loading @@ -61,6 +65,7 @@ import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.nfc.NfcAdapter; import android.os.Build; import android.os.CancellationSignal; Loading Loading @@ -865,10 +870,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } private void handleFingerprintLockoutReset() { boolean changed = mFingerprintLockedOut || mFingerprintLockedOutPermanent; mFingerprintLockedOut = false; mFingerprintLockedOutPermanent = false; private void handleFingerprintLockoutReset(@LockoutMode int mode) { Log.d(TAG, "handleFingerprintLockoutReset: " + mode); final boolean wasLockout = mFingerprintLockedOut; final boolean wasLockoutPermanent = mFingerprintLockedOutPermanent; mFingerprintLockedOut = (mode == BIOMETRIC_LOCKOUT_TIMED) || mode == BIOMETRIC_LOCKOUT_PERMANENT; mFingerprintLockedOutPermanent = (mode == BIOMETRIC_LOCKOUT_PERMANENT); final boolean changed = (mFingerprintLockedOut != wasLockout) || (mFingerprintLockedOutPermanent != wasLockoutPermanent); if (isUdfpsEnrolled()) { // TODO(b/194825098): update the reset signal(s) Loading @@ -878,7 +888,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // be noticeable. mHandler.postDelayed(() -> { updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS); }, getBiometricLockoutDelay()); } else { updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); } Loading Loading @@ -1076,13 +1086,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } private void handleFaceLockoutReset() { boolean changed = mFaceLockedOutPermanent; mFaceLockedOutPermanent = false; private void handleFaceLockoutReset(@LockoutMode int mode) { Log.d(TAG, "handleFaceLockoutReset: " + mode); final boolean wasLockoutPermanent = mFaceLockedOutPermanent; mFaceLockedOutPermanent = (mode == BIOMETRIC_LOCKOUT_PERMANENT); final boolean changed = (mFaceLockedOutPermanent != wasLockoutPermanent); mHandler.postDelayed(() -> { updateFaceListeningState(BIOMETRIC_ACTION_UPDATE); }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS); }, getBiometricLockoutDelay()); if (changed) { notifyLockedOutStateChanged(BiometricSourceType.FACE); Loading Loading @@ -1462,7 +1474,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab = new FingerprintManager.LockoutResetCallback() { @Override public void onLockoutReset(int sensorId) { handleFingerprintLockoutReset(); handleFingerprintLockoutReset(BIOMETRIC_LOCKOUT_NONE); } }; Loading @@ -1470,7 +1482,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab = new FaceManager.LockoutResetCallback() { @Override public void onLockoutReset(int sensorId) { handleFaceLockoutReset(); handleFaceLockoutReset(BIOMETRIC_LOCKOUT_NONE); } }; Loading Loading @@ -1580,10 +1592,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }; private CancellationSignal mFingerprintCancelSignal; private CancellationSignal mFaceCancelSignal; @VisibleForTesting CancellationSignal mFingerprintCancelSignal; @VisibleForTesting CancellationSignal mFaceCancelSignal; private FingerprintManager mFpm; private FaceManager mFaceManager; private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; private List<FaceSensorPropertiesInternal> mFaceSensorProperties; private boolean mFingerprintLockedOut; private boolean mFingerprintLockedOutPermanent; Loading Loading @@ -2018,6 +2033,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); mFingerprintSensorProperties = mFpm.getSensorPropertiesInternal(); } if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { mFaceManager = (FaceManager) context.getSystemService(Context.FACE_SERVICE); Loading Loading @@ -2382,11 +2398,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean shouldListenUdfpsState = !isUdfps || (!userCanSkipBouncer && !isEncryptedOrLockdownForUser && userDoesNotHaveTrust && !mFingerprintLockedOut); && userDoesNotHaveTrust); final boolean shouldListen = shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState && shouldListenUdfpsState; && shouldListenBouncerState && shouldListenUdfpsState && !isFingerprintLockedOut(); if (DEBUG_FINGERPRINT || DEBUG_SPEW) { maybeLogListenerModelData( Loading Loading @@ -2773,6 +2788,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onUserSwitchComplete(userId); } } if (mFaceManager != null && !mFaceSensorProperties.isEmpty()) { handleFaceLockoutReset(mFaceManager.getLockoutModeForUser( mFaceSensorProperties.get(0).sensorId, userId)); } if (mFpm != null && !mFingerprintSensorProperties.isEmpty()) { handleFingerprintLockoutReset(mFpm.getLockoutModeForUser( mFingerprintSensorProperties.get(0).sensorId, userId)); } mInteractionJankMonitor.end(InteractionJankMonitor.CUJ_USER_SWITCH); mLatencyTracker.onActionEnd(LatencyTracker.ACTION_USER_SWITCH); } Loading Loading @@ -3508,6 +3533,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } protected int getBiometricLockoutDelay() { return BIOMETRIC_LOCKOUT_RESET_DELAY_MS; } /** * Unregister all listeners. */ Loading
packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +83 −1 Original line number Diff line number Diff line Loading @@ -35,10 +35,12 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; Loading @@ -50,15 +52,20 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorProperties; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.IRemoteCallback; import android.os.UserHandle; Loading Loading @@ -121,6 +128,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "", DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID, TEST_CARRIER_ID, 0); private static final int FACE_SENSOR_ID = 0; private static final int FINGERPRINT_SENSOR_ID = 1; @Mock private DumpManager mDumpManager; @Mock Loading Loading @@ -212,6 +222,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mFingerprintManager.isHardwareDetected()).thenReturn(true); when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(List.of( new FingerprintSensorPropertiesInternal(1 /* sensorId */, FingerprintSensorProperties.STRENGTH_STRONG, 1 /* maxEnrollmentsPerUser */, List.of(new ComponentInfoInternal("fingerprintSensor" /* componentId */, "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, "00000001" /* serialNumber */, "" /* softwareVersion */)), FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, false /* resetLockoutRequiresHAT */))); when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true); when(mUserManager.isPrimaryUser()).thenReturn(true); when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class)); Loading @@ -232,9 +252,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mSpiedContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); mMockitoSession = ExtendedMockito.mockitoSession() .spyStatic(SubscriptionManager.class).startMocking(); .spyStatic(SubscriptionManager.class) .spyStatic(ActivityManager.class) .startMocking(); ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(SubscriptionManager::getDefaultSubscriptionId); ExtendedMockito.doReturn(KeyguardUpdateMonitor.getCurrentUser()) .when(ActivityManager::getCurrentUser); mTestableLooper = TestableLooper.get(this); allowTestableLooperAsMainThread(); Loading Loading @@ -765,6 +789,59 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { verify(mLatencyTracker).onActionEnd(LatencyTracker.ACTION_USER_SWITCH); } @Test public void testMultiUserLockoutChanged_whenUserSwitches() { testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT, BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT); } @Test public void testMultiUserLockoutNotChanged_whenUserSwitches() { testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_NONE, BiometricConstants.BIOMETRIC_LOCKOUT_NONE); } private void testMultiUserLockout_whenUserSwitches( @BiometricConstants.LockoutMode int fingerprintLockoutMode, @BiometricConstants.LockoutMode int faceLockoutMode) { final int newUser = 12; final boolean faceLocked = faceLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE; final boolean fpLocked = fingerprintLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE; when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), eq(newUser))) .thenReturn(fingerprintLockoutMode); when(mFaceManager.getLockoutModeForUser(eq(FACE_SENSOR_ID), eq(newUser))) .thenReturn(faceLockoutMode); mKeyguardUpdateMonitor.dispatchStartedWakingUp(); mTestableLooper.processAllMessages(); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal); final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal); mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel; mKeyguardUpdateMonitor.mFingerprintCancelSignal = fpCancel; KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class); mKeyguardUpdateMonitor.registerCallback(callback); mKeyguardUpdateMonitor.handleUserSwitchComplete(newUser); mTestableLooper.processAllMessages(); verify(faceCancel, faceLocked ? times(1) : never()).cancel(); verify(fpCancel, fpLocked ? times(1) : never()).cancel(); verify(callback, faceLocked ? times(1) : never()).onBiometricRunningStateChanged( eq(false), eq(BiometricSourceType.FACE)); verify(callback, fpLocked ? times(1) : never()).onBiometricRunningStateChanged( eq(false), eq(BiometricSourceType.FINGERPRINT)); assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(fpLocked); assertThat(mKeyguardUpdateMonitor.isFaceLockedOut()).isEqualTo(faceLocked); } @Test public void testGetUserCanSkipBouncer_whenTrust() { int user = KeyguardUpdateMonitor.getCurrentUser(); Loading Loading @@ -1124,5 +1201,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mSimStateChanged.set(true); super.handleSimStateChange(subId, slotId, state); } @Override protected int getBiometricLockoutDelay() { return 0; } } }