Merge "Update face strong auth strongAuth message" into tm-qpr-dev am: 72ee972de5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21299211

Change-Id: I08e79c39d65f2a0baf8b05542a0c419f9c45f223
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Beverly Tai
2023-02-09 13:55:51 +00:00
committed by Automerger Merge Worker
4 changed files with 114 additions and 10 deletions

View File

@@ -260,6 +260,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting @VisibleForTesting
public static final int BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED = -1; public static final int BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED = -1;
public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2; public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2;
public static final int BIOMETRIC_HELP_FACE_NOT_AVAILABLE = -3;
/** /**
* If no cancel signal has been received after this amount of time, set the biometric running * If no cancel signal has been received after this amount of time, set the biometric running
@@ -2948,9 +2949,26 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// This would need to be updated for multi-sensor devices // This would need to be updated for multi-sensor devices
final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty() final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty()
&& mFaceSensorProperties.get(0).supportsFaceDetection; && mFaceSensorProperties.get(0).supportsFaceDetection;
if (!isUnlockingWithBiometricAllowed(FACE) && supportsFaceDetection) { if (!isUnlockingWithBiometricAllowed(FACE)) {
final boolean udfpsFingerprintAuthRunning = isUdfpsSupported()
&& isFingerprintDetectionRunning();
if (supportsFaceDetection && !udfpsFingerprintAuthRunning) {
// Run face detection. (If a face is detected, show the bouncer.)
mLogger.v("startListeningForFace - detect"); mLogger.v("startListeningForFace - detect");
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId); mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
} else {
// Don't run face detection. Instead, inform the user
// face auth is unavailable and how to proceed.
// (ie: "Use fingerprint instead" or "Swipe up to open")
mLogger.v("Ignoring \"startListeningForFace - detect\". "
+ "Informing user face isn't available.");
mFaceAuthenticationCallback.onAuthenticationHelp(
BIOMETRIC_HELP_FACE_NOT_AVAILABLE,
mContext.getResources().getString(
R.string.keyguard_face_unlock_unavailable)
);
return;
}
} else { } else {
mLogger.v("startListeningForFace - authenticate"); mLogger.v("startListeningForFace - authenticate");
final boolean isBypassEnabled = mKeyguardBypassController != null final boolean isBypassEnabled = mKeyguardBypassController != null

View File

@@ -25,6 +25,7 @@ import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED; import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser; import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
@@ -1084,18 +1085,23 @@ public class KeyguardIndicationController {
} }
} }
final boolean faceAuthUnavailable = biometricSourceType == FACE
&& msgId == BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
// TODO(b/141025588): refactor to reduce repetition of code/comments // TODO(b/141025588): refactor to reduce repetition of code/comments
// Only checking if unlocking with Biometric is allowed (no matter strong or non-strong // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
// as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
// pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
// check of whether non-strong biometric is allowed // check of whether non-strong biometric is allowed
if (!mKeyguardUpdateMonitor if (!mKeyguardUpdateMonitor
.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) { .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
&& !faceAuthUnavailable) {
return; return;
} }
final boolean faceAuthSoftError = biometricSourceType == FACE final boolean faceAuthSoftError = biometricSourceType == FACE
&& msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; && msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
&& msgId != BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
final boolean faceAuthFailed = biometricSourceType == FACE final boolean faceAuthFailed = biometricSourceType == FACE
&& msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed && msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed
final boolean fpAuthFailed = biometricSourceType == FINGERPRINT final boolean fpAuthFailed = biometricSourceType == FINGERPRINT
@@ -1138,6 +1144,13 @@ public class KeyguardIndicationController {
getTrustGrantedIndication(), getTrustGrantedIndication(),
mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock)
); );
} else if (faceAuthUnavailable) {
showBiometricMessage(
helpString,
isUnlockWithFingerprintPossible
? mContext.getString(R.string.keyguard_suggest_fingerprint)
: mContext.getString(R.string.keyguard_unlock)
);
} else { } else {
showBiometricMessage(helpString); showBiometricMessage(helpString);
} }

View File

@@ -27,6 +27,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOM
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_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; 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.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING; import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING;
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT; import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT; import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
@@ -240,7 +241,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Mock @Mock
private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider; private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider;
private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
private final int mCurrentUserId = 100; private final int mCurrentUserId = 100;
private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0); private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0);
@@ -280,9 +281,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
when(mFaceSensorProperties.get(anyInt())).thenReturn( when(mFaceSensorProperties.get(anyInt())).thenReturn(
createFaceSensorProperties(/* supportsFaceDetection = */ false)); createFaceSensorProperties(/* supportsFaceDetection = */ false));
when(mFingerprintManager.isHardwareDetected()).thenReturn(true); mFingerprintSensorProperties = List.of(
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(List.of(
new FingerprintSensorPropertiesInternal(1 /* sensorId */, new FingerprintSensorPropertiesInternal(1 /* sensorId */,
FingerprintSensorProperties.STRENGTH_STRONG, FingerprintSensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */, 1 /* maxEnrollmentsPerUser */,
@@ -291,7 +290,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
"1.01" /* firmwareVersion */, "1.01" /* firmwareVersion */,
"00000001" /* serialNumber */, "" /* softwareVersion */)), "00000001" /* serialNumber */, "" /* softwareVersion */)),
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
false /* resetLockoutRequiresHAT */))); false /* resetLockoutRequiresHAT */));
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(
mFingerprintSensorProperties);
when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true); when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
when(mUserManager.isPrimaryUser()).thenReturn(true); when(mUserManager.isPrimaryUser()).thenReturn(true);
when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class)); when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class));
@@ -769,6 +772,36 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
anyBoolean()); anyBoolean());
} }
@Test
public void nofaceDetect_whenStrongAuthRequiredAndBypassUdfpsSupportedAndFpRunning() {
// GIVEN mocked keyguardUpdateMonitorCallback
KeyguardUpdateMonitorCallback keyguardUpdateMonitorCallback =
mock(KeyguardUpdateMonitorCallback.class);
mKeyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback);
// GIVEN bypass is enabled, face detection is supported
lockscreenBypassIsAllowed();
supportsFaceDetection();
keyguardIsVisible();
// GIVEN udfps is supported and strong auth required for weak biometrics (face) only
givenUdfpsSupported();
strongAuthRequiredForWeakBiometricOnly(); // this allows fingerprint to run but not face
// WHEN the device wakes up
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
// THEN face detect and authenticate are NOT triggered
verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
// THEN biometric help message sent to callback
verify(keyguardUpdateMonitorCallback).onBiometricHelp(
eq(BIOMETRIC_HELP_FACE_NOT_AVAILABLE), anyString(), eq(BiometricSourceType.FACE));
}
@Test @Test
public void faceDetect_whenStrongAuthRequiredAndBypass() { public void faceDetect_whenStrongAuthRequiredAndBypass() {
// GIVEN bypass is enabled, face detection is supported and strong auth is required // GIVEN bypass is enabled, face detection is supported and strong auth is required
@@ -776,6 +809,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
supportsFaceDetection(); supportsFaceDetection();
strongAuthRequiredEncrypted(); strongAuthRequiredEncrypted();
keyguardIsVisible(); keyguardIsVisible();
// fingerprint is NOT running, UDFPS is NOT supported
// WHEN the device wakes up // WHEN the device wakes up
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
@@ -2466,6 +2500,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
} }
private void strongAuthRequiredForWeakBiometricOnly() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(eq(true))).thenReturn(true);
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(eq(false))).thenReturn(false);
}
private void strongAuthNotRequired() { private void strongAuthNotRequired() {
when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser()))
.thenReturn(0); .thenReturn(0);
@@ -2520,6 +2559,12 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
} }
private void givenUdfpsSupported() {
Assert.assertFalse(mFingerprintSensorProperties.isEmpty());
when(mAuthController.getUdfpsProps()).thenReturn(mFingerprintSensorProperties);
Assert.assertTrue(mKeyguardUpdateMonitor.isUdfpsSupported());
}
private void setBroadcastReceiverPendingResult(BroadcastReceiver receiver) { private void setBroadcastReceiverPendingResult(BroadcastReceiver receiver) {
BroadcastReceiver.PendingResult pendingResult = BroadcastReceiver.PendingResult pendingResult =
new BroadcastReceiver.PendingResult(Activity.RESULT_OK, new BroadcastReceiver.PendingResult(Activity.RESULT_OK,

View File

@@ -23,6 +23,7 @@ import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_T
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED; import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
@@ -619,6 +620,33 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mContext.getString(R.string.keyguard_suggest_fingerprint)); mContext.getString(R.string.keyguard_suggest_fingerprint));
} }
@Test
public void onBiometricHelp_coEx_faceUnavailable() {
createController();
// GIVEN unlocking with fingerprint is possible
when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(anyInt()))
.thenReturn(true);
String message = "A message";
mController.setVisible(true);
// WHEN there's a face unavailable message
mController.getKeyguardCallback().onBiometricHelp(
BIOMETRIC_HELP_FACE_NOT_AVAILABLE,
message,
BiometricSourceType.FACE);
// THEN show sequential messages such as: 'face unlock unavailable' and
// 'try fingerprint instead'
verifyIndicationMessage(
INDICATION_TYPE_BIOMETRIC_MESSAGE,
message);
verifyIndicationMessage(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
mContext.getString(R.string.keyguard_suggest_fingerprint));
}
@Test @Test
public void onBiometricHelp_coEx_fpFailure_faceAlreadyUnlocked() { public void onBiometricHelp_coEx_fpFailure_faceAlreadyUnlocked() {
createController(); createController();