diff options
author | 2022-12-02 21:05:40 +0000 | |
---|---|---|
committer | 2022-12-02 21:05:40 +0000 | |
commit | 4b4e6b1ed6a121d19dee34e9813432b4d5ef4e98 (patch) | |
tree | 8605506f6cc4ef67dbf06f214c194015f9fa448b | |
parent | e08798d60aa5fec390bcf551b9a82aa1c50edc11 (diff) | |
parent | 5e844042a12233ff86f04ac04516119a6765b1b2 (diff) |
Merge "On strongAuthChanges, update fp & face states"
5 files changed, 273 insertions, 141 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt index 4a41b3fe2589..5bb9367fa4a5 100644 --- a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt +++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt @@ -48,11 +48,13 @@ import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_INIT import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_OCCLUSION_CHANGED import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_RESET import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_VISIBILITY_CHANGED +import com.android.keyguard.InternalFaceAuthReasons.NON_STRONG_BIOMETRIC_ALLOWED_CHANGED import com.android.keyguard.InternalFaceAuthReasons.OCCLUDING_APP_REQUESTED import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN import com.android.keyguard.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE import com.android.keyguard.InternalFaceAuthReasons.STARTED_WAKING_UP +import com.android.keyguard.InternalFaceAuthReasons.STRONG_AUTH_ALLOWED_CHANGED import com.android.keyguard.InternalFaceAuthReasons.TRUST_DISABLED import com.android.keyguard.InternalFaceAuthReasons.TRUST_ENABLED import com.android.keyguard.InternalFaceAuthReasons.USER_SWITCHING @@ -121,6 +123,9 @@ private object InternalFaceAuthReasons { const val FACE_AUTHENTICATED = "Face auth started/stopped because face is authenticated" const val BIOMETRIC_ENABLED = "Face auth started/stopped because biometric is enabled on keyguard" + const val STRONG_AUTH_ALLOWED_CHANGED = "Face auth stopped because strong auth allowed changed" + const val NON_STRONG_BIOMETRIC_ALLOWED_CHANGED = + "Face auth stopped because non strong biometric allowed changed" } /** @@ -204,7 +209,11 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) : @UiEvent(doc = FACE_AUTHENTICATED) FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED(1187, FACE_AUTHENTICATED), @UiEvent(doc = BIOMETRIC_ENABLED) - FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED); + FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED), + @UiEvent(doc = STRONG_AUTH_ALLOWED_CHANGED) + FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED), + @UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED) + FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED); override fun getId(): Int = this.id diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt index e6283b86283b..52ca1668e4c9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt @@ -53,17 +53,17 @@ data class KeyguardFaceListenModel( val biometricSettingEnabledForUser: Boolean, val bouncerFullyShown: Boolean, val faceAndFpNotAuthenticated: Boolean, + val faceAuthAllowed: Boolean, val faceDisabled: Boolean, val faceLockedOut: Boolean, - val fpLockedOut: Boolean, val goingToSleep: Boolean, val keyguardAwake: Boolean, val keyguardGoingAway: Boolean, val listeningForFaceAssistant: Boolean, val occludingAppRequestingFaceAuth: Boolean, val primaryUser: Boolean, - val scanningAllowedByStrongAuth: Boolean, val secureCameraLaunched: Boolean, + val supportsDetect: Boolean, val switchingUser: Boolean, val udfpsBouncerShowing: Boolean, val udfpsFingerDown: Boolean, @@ -79,9 +79,8 @@ data class KeyguardActiveUnlockModel( // keep sorted val awakeKeyguard: Boolean, val authInterruptActive: Boolean, - val encryptedOrTimedOut: Boolean, - val fpLockout: Boolean, - val lockDown: Boolean, + val fpLockedOut: Boolean, + val primaryAuthRequired: Boolean, val switchingUser: Boolean, val triggerActiveUnlockForAssistant: Boolean, val userCanDismissLockScreen: Boolean diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 64fa15e0cd20..479d4549016c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -34,9 +34,9 @@ import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; -import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent; +import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED; import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED; import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED; import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP; @@ -65,6 +65,7 @@ import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_FACE_AUT import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_KEYGUARD_INIT; import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN; import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP; +import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED; import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING; import static com.android.systemui.DejankUtils.whitelistIpcs; @@ -170,7 +171,6 @@ import java.util.Map.Entry; import java.util.Set; import java.util.TimeZone; import java.util.concurrent.Executor; -import java.util.function.Consumer; import java.util.stream.Collectors; import javax.inject.Inject; @@ -1401,6 +1401,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } + /** + * Whether the user locked down the device. This doesn't include device policy manager lockdown. + */ public boolean isUserInLockdown(int userId) { return containsFlag(mStrongAuthTracker.getStrongAuthForUser(userId), STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); @@ -1432,7 +1435,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return mStrongAuthTracker; } - private void notifyStrongAuthStateChanged(int userId) { + @VisibleForTesting + void notifyStrongAuthAllowedChanged(int userId) { Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1440,6 +1444,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onStrongAuthStateChanged(userId); } } + if (userId == getCurrentUser()) { + FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED.setExtraInfo( + mStrongAuthTracker.getStrongAuthForUser(getCurrentUser())); + + // Strong auth is only reset when primary auth is used to enter the device, + // so we only check whether to stop biometric listening states here + updateBiometricListeningState( + BIOMETRIC_ACTION_STOP, FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED); + } } private void notifyLockedOutStateChanged(BiometricSourceType type) { @@ -1451,8 +1464,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } } - - private void notifyNonStrongBiometricStateChanged(int userId) { + @VisibleForTesting + void notifyNonStrongBiometricAllowedChanged(int userId) { Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1460,6 +1473,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onNonStrongBiometricAllowedChanged(userId); } } + if (userId == getCurrentUser()) { + FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED.setExtraInfo( + mStrongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout( + getCurrentUser()) ? -1 : 1); + + // This is only reset when primary auth is used to enter the device, so we only check + // whether to stop biometric listening states here + updateBiometricListeningState(BIOMETRIC_ACTION_STOP, + FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED); + } } private void dispatchErrorMessage(CharSequence message) { @@ -1805,16 +1828,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - public static class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { - private final Consumer<Integer> mStrongAuthRequiredChangedCallback; - private final Consumer<Integer> mNonStrongBiometricAllowedChanged; - - public StrongAuthTracker(Context context, - Consumer<Integer> strongAuthRequiredChangedCallback, - Consumer<Integer> nonStrongBiometricAllowedChanged) { + /** + * Updates callbacks when strong auth requirements change. + */ + public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { + public StrongAuthTracker(Context context) { super(context); - mStrongAuthRequiredChangedCallback = strongAuthRequiredChangedCallback; - mNonStrongBiometricAllowedChanged = nonStrongBiometricAllowedChanged; } public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) { @@ -1830,7 +1849,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onStrongAuthRequiredChanged(int userId) { - mStrongAuthRequiredChangedCallback.accept(userId); + notifyStrongAuthAllowedChanged(userId); } // TODO(b/247091681): Renaming the inappropriate onIsNonStrongBiometricAllowedChanged @@ -1838,7 +1857,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // Strong-Auth @Override public void onIsNonStrongBiometricAllowedChanged(int userId) { - mNonStrongBiometricAllowedChanged.accept(userId); + notifyNonStrongBiometricAllowedChanged(userId); } } @@ -1999,8 +2018,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mUserTracker = userTracker; mTelephonyListenerManager = telephonyListenerManager; mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); - mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged, - this::notifyNonStrongBiometricStateChanged); + mStrongAuthTracker = new StrongAuthTracker(context); mBackgroundExecutor = backgroundExecutor; mBroadcastDispatcher = broadcastDispatcher; mInteractionJankMonitor = interactionJankMonitor; @@ -2575,24 +2593,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || !mLockPatternUtils.isSecure(user); // Don't trigger active unlock if fp is locked out - final boolean fpLockedout = mFingerprintLockedOut || mFingerprintLockedOutPermanent; + final boolean fpLockedOut = mFingerprintLockedOut || mFingerprintLockedOutPermanent; // Don't trigger active unlock if primary auth is required - final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user); - final boolean isLockDown = - containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) - || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); - final boolean isEncryptedOrTimedOut = - containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT) - || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT); + final boolean primaryAuthRequired = !isUnlockingWithBiometricAllowed(true); final boolean shouldTriggerActiveUnlock = (mAuthInterruptActive || triggerActiveUnlockForAssistant || awakeKeyguard) && !mSwitchingUser && !userCanDismissLockScreen - && !fpLockedout - && !isLockDown - && !isEncryptedOrTimedOut + && !fpLockedOut + && !primaryAuthRequired && !mKeyguardGoingAway && !mSecureCameraLaunched; @@ -2604,9 +2615,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab shouldTriggerActiveUnlock, awakeKeyguard, mAuthInterruptActive, - isEncryptedOrTimedOut, - fpLockedout, - isLockDown, + fpLockedOut, + primaryAuthRequired, mSwitchingUser, triggerActiveUnlockForAssistant, userCanDismissLockScreen)); @@ -2658,7 +2668,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab && !fingerprintDisabledForUser && (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser - && biometricEnabledForUser; + && biometricEnabledForUser + && !isUserInLockdown(user); final boolean strongerAuthRequired = !isUnlockingWithFingerprintAllowed(); final boolean isSideFps = isSfpsSupported() && isSfpsEnrolled(); final boolean shouldListenBouncerState = @@ -2720,14 +2731,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean awakeKeyguard = isKeyguardVisible() && mDeviceInteractive && !statusBarShadeLocked; final int user = getCurrentUser(); - final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user); - final boolean isLockDown = - containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) - || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); - final boolean isEncryptedOrTimedOut = - containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT) - || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT); - final boolean fpLockedOut = isFingerprintLockedOut(); + final boolean faceAuthAllowed = isUnlockingWithBiometricAllowed(FACE); final boolean canBypass = mKeyguardBypassController != null && mKeyguardBypassController.canBypass(); // There's no reason to ask the HAL for authentication when the user can dismiss the @@ -2735,20 +2739,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // the lock screen even when TrustAgents are keeping the device unlocked. final boolean userNotTrustedOrDetectionIsNeeded = !getUserHasTrust(user) || canBypass; - // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing. - // Lock-down mode shouldn't scan, since it is more explicit. - boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass - && !mPrimaryBouncerFullyShown); - - // If the device supports face detection (without authentication) and bypass is enabled, - // allow face scanning to happen if the device is in lockdown mode. - // Otherwise, prevent scanning. - final boolean supportsDetectOnly = !mFaceSensorProperties.isEmpty() - && canBypass - && mFaceSensorProperties.get(0).supportsFaceDetection; - if (isLockDown && !supportsDetectOnly) { - strongAuthAllowsScanning = false; - } + // If the device supports face detection (without authentication), if bypass is enabled, + // allow face detection to happen even if stronger auth is required. When face is detected, + // we show the bouncer. However, if the user manually locked down the device themselves, + // never attempt to detect face. + final boolean supportsDetect = !mFaceSensorProperties.isEmpty() + && mFaceSensorProperties.get(0).supportsFaceDetection + && canBypass && !mPrimaryBouncerIsOrWillBeShowing + && !isUserInLockdown(user); + final boolean faceAuthAllowedOrDetectionIsNeeded = faceAuthAllowed || supportsDetect; // If the face or fp has recently been authenticated do not attempt to authenticate again. final boolean faceAndFpNotAuthenticated = !getUserUnlockedWithBiometric(user); @@ -2769,14 +2768,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || mUdfpsBouncerShowing) && !mSwitchingUser && !faceDisabledForUser && userNotTrustedOrDetectionIsNeeded && !mKeyguardGoingAway && biometricEnabledForUser - && strongAuthAllowsScanning && mIsPrimaryUser + && faceAuthAllowedOrDetectionIsNeeded && mIsPrimaryUser && (!mSecureCameraLaunched || mOccludingAppRequestingFace) && faceAndFpNotAuthenticated - && !mGoingToSleep - // We only care about fp locked out state and not face because we still trigger - // face auth even when face is locked out to show the user a message that face - // unlock was supposed to run but didn't - && !fpLockedOut; + && !mGoingToSleep; // Aggregate relevant fields for debug logging. maybeLogListenerModelData( @@ -2786,19 +2781,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab shouldListen, mAuthInterruptActive, biometricEnabledForUser, - mPrimaryBouncerFullyShown, + mPrimaryBouncerFullyShown, faceAndFpNotAuthenticated, + faceAuthAllowed, faceDisabledForUser, isFaceLockedOut(), - fpLockedOut, mGoingToSleep, awakeKeyguard, mKeyguardGoingAway, shouldListenForFaceAssistant, mOccludingAppRequestingFace, mIsPrimaryUser, - strongAuthAllowsScanning, mSecureCameraLaunched, + supportsDetect, mSwitchingUser, mUdfpsBouncerShowing, isUdfpsFingerDown, @@ -2902,9 +2897,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // This would need to be updated for multi-sensor devices final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty() && mFaceSensorProperties.get(0).supportsFaceDetection; - if (isEncryptedOrLockdown(userId) && supportsFaceDetection) { + if (!isUnlockingWithBiometricAllowed(FACE) && supportsFaceDetection) { + mLogger.v("startListeningForFace - detect"); mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId); } else { + mLogger.v("startListeningForFace - authenticate"); final boolean isBypassEnabled = mKeyguardBypassController != null && mKeyguardBypassController.isBypassEnabled(); mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt index afd582a3b822..fa8c8982bccb 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt @@ -87,17 +87,17 @@ private fun faceModel(user: Int) = KeyguardFaceListenModel( biometricSettingEnabledForUser = false, bouncerFullyShown = false, faceAndFpNotAuthenticated = false, + faceAuthAllowed = true, faceDisabled = false, faceLockedOut = false, - fpLockedOut = false, goingToSleep = false, keyguardAwake = false, keyguardGoingAway = false, listeningForFaceAssistant = false, occludingAppRequestingFaceAuth = false, primaryUser = false, - scanningAllowedByStrongAuth = false, secureCameraLaunched = false, + supportsDetect = true, switchingUser = false, udfpsBouncerShowing = false, udfpsFingerDown = false, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 4e358ddd49ea..f0d651a90cd0 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -27,6 +27,7 @@ import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; +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_STATE_CANCELLING_RESTARTING; import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT; @@ -101,6 +102,8 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import androidx.annotation.NonNull; + import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.InstanceId; @@ -267,21 +270,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // IBiometricsFace@1.0 does not support detection, only authentication. when(mFaceSensorProperties.isEmpty()).thenReturn(false); + when(mFaceSensorProperties.get(anyInt())).thenReturn( + createFaceSensorProperties(/* supportsFaceDetection = */ false)); - final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); - componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, - "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, - "00000001" /* serialNumber */, "" /* softwareVersion */)); - componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */, - "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, - "vendor/version/revision" /* softwareVersion */)); - - when(mFaceSensorProperties.get(anyInt())).thenReturn(new FaceSensorPropertiesInternal( - 0 /* id */, - FaceSensorProperties.STRENGTH_STRONG, 1 /* maxTemplatesAllowed */, - componentInfo, FaceSensorProperties.TYPE_UNKNOWN, - false /* supportsFaceDetection */, true /* supportsSelfIllumination */, - false /* resetLockoutRequiresChallenge */)); when(mFingerprintManager.isHardwareDetected()).thenReturn(true); when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(List.of( @@ -354,6 +345,28 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mAuthController.areAllFingerprintAuthenticatorsRegistered()).thenReturn(true); } + @NonNull + private FaceSensorPropertiesInternal createFaceSensorProperties(boolean supportsFaceDetection) { + final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); + componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, + "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, + "00000001" /* serialNumber */, "" /* softwareVersion */)); + componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */, + "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, + "vendor/version/revision" /* softwareVersion */)); + + + return new FaceSensorPropertiesInternal( + 0 /* id */, + FaceSensorProperties.STRENGTH_STRONG, + 1 /* maxTemplatesAllowed */, + componentInfo, + FaceSensorProperties.TYPE_UNKNOWN, + supportsFaceDetection /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresChallenge */); + } + @After public void tearDown() { if (mMockitoSession != null) { @@ -611,7 +624,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testUnlockingWithFaceAllowed_strongAuthTrackerUnlockingWithBiometricAllowed() { // GIVEN unlocking with biometric is allowed - when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); + strongAuthNotRequired(); // THEN unlocking with face and fp is allowed Assert.assertTrue(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( @@ -633,7 +646,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testUnlockingWithFaceAllowed_fingerprintLockout() { // GIVEN unlocking with biometric is allowed - when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); + strongAuthNotRequired(); // WHEN fingerprint is locked out fingerprintErrorLockedOut(); @@ -656,7 +669,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testUnlockingWithFpAllowed_fingerprintLockout() { // GIVEN unlocking with biometric is allowed - when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); + strongAuthNotRequired(); // WHEN fingerprint is locked out fingerprintErrorLockedOut(); @@ -710,10 +723,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void skipsAuthentication_whenEncryptedKeyguard() { - when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn( - STRONG_AUTH_REQUIRED_AFTER_BOOT); - mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); + public void skipsAuthentication_whenStrongAuthRequired_nonBypass() { + lockscreenBypassIsNotAllowed(); + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); mTestableLooper.processAllMessages(); @@ -723,15 +735,48 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void requiresAuthentication_whenEncryptedKeyguard_andBypass() { - testStrongAuthExceptOnBouncer( - STRONG_AUTH_REQUIRED_AFTER_BOOT); + public void faceDetect_whenStrongAuthRequiredAndBypass() { + // GIVEN bypass is enabled, face detection is supported and strong auth is required + lockscreenBypassIsAllowed(); + supportsFaceDetection(); + strongAuthRequiredEncrypted(); + keyguardIsVisible(); + + // WHEN the device wakes up + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mTestableLooper.processAllMessages(); + + // FACE detect is triggered, not authenticate + verify(mFaceManager).detectFace(any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), + anyBoolean()); + + // WHEN bouncer becomes visible + setKeyguardBouncerVisibility(true); + clearInvocations(mFaceManager); + + // THEN face scanning is not run + mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), + anyBoolean()); + verify(mFaceManager, never()).detectFace(any(), any(), anyInt()); } @Test - public void requiresAuthentication_whenTimeoutKeyguard_andBypass() { - testStrongAuthExceptOnBouncer( - KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT); + public void noFaceDetect_whenStrongAuthRequiredAndBypass_faceDetectionUnsupported() { + // GIVEN bypass is enabled, face detection is NOT supported and strong auth is required + lockscreenBypassIsAllowed(); + strongAuthRequiredEncrypted(); + keyguardIsVisible(); + + // WHEN the device wakes up + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mTestableLooper.processAllMessages(); + + // FACE detect and authenticate are NOT triggered + verify(mFaceManager, never()).detectFace(any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), + anyBoolean()); } @Test @@ -764,24 +809,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(didFaceAuthRun).isFalse(); } - private void testStrongAuthExceptOnBouncer(int strongAuth) { - when(mKeyguardBypassController.canBypass()).thenReturn(true); - mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); - when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth); - - mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); - mTestableLooper.processAllMessages(); - keyguardIsVisible(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); - - // Stop scanning when bouncer becomes visible - setKeyguardBouncerVisibility(true); - clearInvocations(mFaceManager); - mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); - } - @Test public void testTriesToAuthenticate_whenAssistant() { mKeyguardUpdateMonitor.setKeyguardShowing(true, true); @@ -792,10 +819,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testTriesToAuthenticate_whenTrustOnAgentKeyguard_ifBypass() { - mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); mTestableLooper.processAllMessages(); - when(mKeyguardBypassController.canBypass()).thenReturn(true); + lockscreenBypassIsAllowed(); mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>()); @@ -815,26 +841,17 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void testIgnoresAuth_whenLockdown() { + public void testNoFaceAuth_whenLockDown() { + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); + userDeviceLockDown(); + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + keyguardIsVisible(); mTestableLooper.processAllMessages(); - when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn( - KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); - keyguardIsVisible(); verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); - } - - @Test - public void testTriesToAuthenticate_whenLockout() { - mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); - mTestableLooper.processAllMessages(); - when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn( - KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT); - - keyguardIsVisible(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager, never()).detectFace(any(), any(), anyInt()); } @Test @@ -977,8 +994,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); -// resetFaceManager(); -// resetFingerprintManager(); when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), eq(newUser))) .thenReturn(fingerprintLockoutMode); @@ -1321,7 +1336,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED); setKeyguardBouncerVisibility(false /* isVisible */); mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); - when(mKeyguardBypassController.canBypass()).thenReturn(true); + lockscreenBypassIsAllowed(); keyguardIsVisible(); // WHEN status bar state reports a change to the keyguard that would normally indicate to @@ -1505,11 +1520,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { userNotCurrentlySwitching(); // This disables face auth - when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) - .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT); + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); mTestableLooper.processAllMessages(); - assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse(); } @@ -1973,6 +1986,109 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { ); } + @Test + public void testStrongAuthChange_lockDown_stopsFpAndFaceListeningState() { + // GIVEN device is listening for face and fingerprint + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mTestableLooper.processAllMessages(); + keyguardIsVisible(); + + 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); + + // WHEN strong auth changes and device is in user lockdown + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); + userDeviceLockDown(); + mKeyguardUpdateMonitor.notifyStrongAuthAllowedChanged(getCurrentUser()); + mTestableLooper.processAllMessages(); + + // THEN face and fingerprint listening are cancelled + verify(faceCancel).cancel(); + verify(callback).onBiometricRunningStateChanged( + eq(false), eq(BiometricSourceType.FACE)); + verify(fpCancel).cancel(); + verify(callback).onBiometricRunningStateChanged( + eq(false), eq(BiometricSourceType.FINGERPRINT)); + } + + @Test + public void testNonStrongBiometricAllowedChanged_stopsFaceListeningState() { + // GIVEN device is listening for face and fingerprint + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mTestableLooper.processAllMessages(); + keyguardIsVisible(); + + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + + final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal); + mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel; + KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class); + mKeyguardUpdateMonitor.registerCallback(callback); + + // WHEN non-strong biometric allowed changes + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); + mKeyguardUpdateMonitor.notifyNonStrongBiometricAllowedChanged(getCurrentUser()); + mTestableLooper.processAllMessages(); + + // THEN face and fingerprint listening are cancelled + verify(faceCancel).cancel(); + verify(callback).onBiometricRunningStateChanged( + eq(false), eq(BiometricSourceType.FACE)); + } + + @Test + public void testShouldListenForFace_withLockedDown_returnsFalse() + throws RemoteException { + keyguardNotGoingAway(); + bouncerFullyVisibleAndNotGoingToSleep(); + currentUserIsPrimary(); + currentUserDoesNotHaveTrust(); + biometricsNotDisabledThroughDevicePolicyManager(); + biometricsEnabledForCurrentUser(); + userNotCurrentlySwitching(); + supportsFaceDetection(); + mTestableLooper.processAllMessages(); + + assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue(); + + userDeviceLockDown(); + + assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse(); + } + + private void userDeviceLockDown() { + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); + when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId)) + .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); + } + + private void supportsFaceDetection() { + when(mFaceSensorProperties.get(anyInt())) + .thenReturn(createFaceSensorProperties( + /* supportsFaceDetection = */ true)); + } + + private void lockscreenBypassIsAllowed() { + mockCanBypassLockscreen(true); + } + + private void mockCanBypassLockscreen(boolean canBypass) { + mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); + when(mKeyguardBypassController.canBypass()).thenReturn(canBypass); + } + + private void lockscreenBypassIsNotAllowed() { + mockCanBypassLockscreen(false); + } + private void cleanupKeyguardUpdateMonitor() { if (mKeyguardUpdateMonitor != null) { mKeyguardUpdateMonitor.removeCallback(mTestCallback); @@ -2066,9 +2182,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { ); } + private void strongAuthRequiredEncrypted() { + when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT); + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); + } + private void strongAuthNotRequired() { when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) .thenReturn(0); + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); } private void currentUserDoesNotHaveTrust() { @@ -2109,6 +2232,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { setKeyguardBouncerVisibility(true); } + private void bouncerNotVisible() { + setKeyguardBouncerVisibility(false); + } + private void setKeyguardBouncerVisibility(boolean isVisible) { mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(isVisible, isVisible); mTestableLooper.processAllMessages(); |