Merge "Update FP failure logic when device is unlocked" into tm-qpr-dev

This commit is contained in:
Beverly Tai
2023-02-03 18:37:15 +00:00
committed by Android (Google) Code Review
5 changed files with 161 additions and 23 deletions

View File

@@ -1311,7 +1311,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
public boolean getUserHasTrust(int userId) {
return !isTrustDisabled() && mUserHasTrust.get(userId);
return !isTrustDisabled() && mUserHasTrust.get(userId)
&& isUnlockingWithTrustAgentAllowed();
}
/**
@@ -1319,12 +1320,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
*/
public boolean getUserUnlockedWithBiometric(int userId) {
BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
boolean fingerprintAllowed = fingerprint != null && fingerprint.mAuthenticated
&& isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric);
boolean faceAllowed = face != null && face.mAuthenticated
return fingerprintAllowed || getUserUnlockedWithFace(userId);
}
/**
* Returns whether the user is unlocked with face.
*/
public boolean getUserUnlockedWithFace(int userId) {
BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
return face != null && face.mAuthenticated
&& isUnlockingWithBiometricAllowed(face.mIsStrongBiometric);
return fingerprintAllowed || faceAllowed;
}
/**
@@ -1399,6 +1407,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return mUserTrustIsUsuallyManaged.get(userId);
}
private boolean isUnlockingWithTrustAgentAllowed() {
return isUnlockingWithBiometricAllowed(true);
}
public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
// StrongAuthTracker#isUnlockingWithBiometricAllowed includes
// STRONG_AUTH_REQUIRED_AFTER_LOCKOUT which is the same as mFingerprintLockedOutPermanent;

View File

@@ -26,6 +26,7 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE;
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.getCurrentUser;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
@@ -539,23 +540,23 @@ public class KeyguardIndicationController {
.build(),
true
);
if (!TextUtils.isEmpty(mBiometricMessageFollowUp)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
new KeyguardIndication.Builder()
.setMessage(mBiometricMessageFollowUp)
.setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
.setTextColor(mInitialTextColorState)
.build(),
true
);
} else {
mRotateTextViewController.hideIndication(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP);
}
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE);
mRotateTextViewController.hideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP);
mRotateTextViewController.hideIndication(
INDICATION_TYPE_BIOMETRIC_MESSAGE);
}
if (!TextUtils.isEmpty(mBiometricMessageFollowUp)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
new KeyguardIndication.Builder()
.setMessage(mBiometricMessageFollowUp)
.setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
.setTextColor(mInitialTextColorState)
.build(),
true
);
} else {
mRotateTextViewController.hideIndication(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP);
}
}
@@ -784,7 +785,8 @@ public class KeyguardIndicationController {
*/
private void showBiometricMessage(CharSequence biometricMessage,
@Nullable CharSequence biometricMessageFollowUp) {
if (TextUtils.equals(biometricMessage, mBiometricMessage)) {
if (TextUtils.equals(biometricMessage, mBiometricMessage)
&& TextUtils.equals(biometricMessageFollowUp, mBiometricMessageFollowUp)) {
return;
}
@@ -793,7 +795,8 @@ public class KeyguardIndicationController {
mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
hideBiometricMessageDelayed(
mBiometricMessageFollowUp != null
!TextUtils.isEmpty(mBiometricMessage)
&& !TextUtils.isEmpty(mBiometricMessageFollowUp)
? IMPORTANT_MSG_MIN_DURATION * 2
: DEFAULT_HIDE_DELAY_MS
);
@@ -1091,6 +1094,8 @@ public class KeyguardIndicationController {
&& msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
final boolean faceAuthFailed = biometricSourceType == FACE
&& msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed
final boolean fpAuthFailed = biometricSourceType == FINGERPRINT
&& msgId == BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED; // ran matcher & failed
final boolean isUnlockWithFingerprintPossible = canUnlockWithFingerprint();
final boolean isCoExFaceAcquisitionMessage =
faceAuthSoftError && isUnlockWithFingerprintPossible;
@@ -1113,6 +1118,22 @@ public class KeyguardIndicationController {
mContext.getString(R.string.keyguard_face_failed),
mContext.getString(R.string.keyguard_suggest_fingerprint)
);
} else if (fpAuthFailed
&& mKeyguardUpdateMonitor.getUserUnlockedWithFace(getCurrentUser())) {
// face had already previously unlocked the device, so instead of showing a
// fingerprint error, tell them they have already unlocked with face auth
// and how to enter their device
showBiometricMessage(
mContext.getString(R.string.keyguard_face_successful_unlock),
mContext.getString(R.string.keyguard_unlock)
);
} else if (fpAuthFailed
&& mKeyguardUpdateMonitor.getUserHasTrust(
KeyguardUpdateMonitor.getCurrentUser())) {
showBiometricMessage(
getTrustGrantedIndication(),
mContext.getString(R.string.keyguard_unlock)
);
} else {
showBiometricMessage(helpString);
}

View File

@@ -437,6 +437,11 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
update(false /* updateAlways */);
}
@Override
public void onLockedOutStateChanged(BiometricSourceType biometricSourceType) {
update(false /* updateAlways */);
}
@Override
public void onKeyguardVisibilityChanged(boolean visible) {
update(false /* updateAlways */);

View File

@@ -685,11 +685,35 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// WHEN fingerprint is locked out
fingerprintErrorLockedOut();
// THEN unlocking with fingeprint is not allowed
// THEN unlocking with fingerprint is not allowed
Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
BiometricSourceType.FINGERPRINT));
}
@Test
public void trustAgentHasTrust() {
// WHEN user has trust
mKeyguardUpdateMonitor.onTrustChanged(true, true, getCurrentUser(), 0, null);
// THEN user is considered as "having trust" and bouncer can be skipped
Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
Assert.assertTrue(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()));
}
@Test
public void trustAgentHasTrust_fingerprintLockout() {
// GIVEN user has trust
mKeyguardUpdateMonitor.onTrustChanged(true, true, getCurrentUser(), 0, null);
Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
// WHEN fingerprint is locked out
fingerprintErrorLockedOut();
// THEN user is NOT considered as "having trust" and bouncer cannot be skipped
Assert.assertFalse(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
Assert.assertFalse(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()));
}
@Test
public void testTriesToAuthenticate_whenBouncer() {
setKeyguardBouncerVisibility(true);

View File

@@ -619,6 +619,82 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mContext.getString(R.string.keyguard_suggest_fingerprint));
}
@Test
public void onBiometricHelp_coEx_fpFailure_faceAlreadyUnlocked() {
createController();
// GIVEN face has already unlocked the device
when(mKeyguardUpdateMonitor.getUserUnlockedWithFace(anyInt())).thenReturn(true);
String message = "A message";
mController.setVisible(true);
// WHEN there's a fingerprint not recognized message
mController.getKeyguardCallback().onBiometricHelp(
BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
message,
BiometricSourceType.FINGERPRINT);
// THEN show sequential messages such as: 'Unlocked by face' and
// 'Swipe up to open'
verifyIndicationMessage(
INDICATION_TYPE_BIOMETRIC_MESSAGE,
mContext.getString(R.string.keyguard_face_successful_unlock));
verifyIndicationMessage(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
mContext.getString(R.string.keyguard_unlock));
}
@Test
public void onBiometricHelp_coEx_fpFailure_trustAgentAlreadyUnlocked() {
createController();
// GIVEN trust agent has already unlocked the device
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
String message = "A message";
mController.setVisible(true);
// WHEN there's a fingerprint not recognized message
mController.getKeyguardCallback().onBiometricHelp(
BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
message,
BiometricSourceType.FINGERPRINT);
// THEN show sequential messages such as: 'Kept unlocked by TrustAgent' and
// 'Swipe up to open'
verifyIndicationMessage(
INDICATION_TYPE_BIOMETRIC_MESSAGE,
mContext.getString(R.string.keyguard_indication_trust_unlocked));
verifyIndicationMessage(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
mContext.getString(R.string.keyguard_unlock));
}
@Test
public void onBiometricHelp_coEx_fpFailure_trustAgentUnlocked_emptyTrustGrantedMessage() {
createController();
// GIVEN trust agent has already unlocked the device & trust granted message is empty
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
mController.showTrustGrantedMessage(false, "");
String message = "A message";
mController.setVisible(true);
// WHEN there's a fingerprint not recognized message
mController.getKeyguardCallback().onBiometricHelp(
BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
message,
BiometricSourceType.FINGERPRINT);
// THEN show action to unlock (ie: 'Swipe up to open')
verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
verifyIndicationMessage(
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
mContext.getString(R.string.keyguard_unlock));
}
@Test
public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromError() {
createController();