summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Beverly <beverlyt@google.com> 2022-11-30 16:24:10 +0000
committer Beverly Tai <beverlyt@google.com> 2022-12-02 14:24:06 +0000
commit5e844042a12233ff86f04ac04516119a6765b1b2 (patch)
treea8045c2c055db65dc18653d04174192fcc7080ba
parent129a1053d2a57d914fda55492b30c24d29313178 (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
-rw-r--r--packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java127
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java263
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();