diff options
| author | 2022-11-30 16:24:10 +0000 | |
|---|---|---|
| committer | 2022-12-02 14:24:06 +0000 | |
| commit | 5e844042a12233ff86f04ac04516119a6765b1b2 (patch) | |
| tree | a8045c2c055db65dc18653d04174192fcc7080ba | |
| parent | 129a1053d2a57d914fda55492b30c24d29313178 (diff) | |
On strongAuthChanges, update fp & face states
Previously, we relied on other state to update which
would trigger updateBiometricListeningState. Instead
of relying on other triggers, directly update
the biometric listening state if strong auth
or non-strong auth allowed states change.
Don't run face auth or detect if device is locked down by the
user. However, if bypass is enabled and the other strongauth
requirements are triggered (ie: idle timeout, timeout, encrypted,
dpm lockdown, after boot), then run detectFace if its supported.
Bug: 259908246
Bug: 258513069
Bug: 260682144
Test: atest KeyguardUpdateMonitorTest
Change-Id: If03a1525832dfb8366c36757ebc84c0dead51b9f
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(); |