Update co-ex face failure message
Suggest to the user to use their fp sensor.
Test: atest KeyguardIndicationControllerTest
Test: enroll fingerprint and a different face. Then attempt
to authenticate with face, and receive a failure (matcher must run and not
recognize face). Observe two messages: "Can't recongize face" and
then, "Use fingerprint instead"
Fixes: 231382377
Change-Id: Ie969e0b1403a530ac589a8a121581656977c82a7
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 8fa2204..d90156d 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -217,7 +217,7 @@
the force lock button. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_user_request">Device was locked manually</string>
- <!-- Face hint message when finger was not recognized. [CHAR LIMIT=20] -->
+ <!-- Face hint message when face was not recognized. [CHAR LIMIT=20] -->
<string name="kg_face_not_recognized">Not recognized</string>
<!-- Error message indicating that the camera privacy sensor has been turned on [CHAR LIMIT=53] -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e4fefc7..aedeb5f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -389,6 +389,10 @@
<string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string>
<!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
<string name="keyguard_face_failed_use_fp">@string/fingerprint_dialog_use_fingerprint_instead</string>
+ <!-- Message shown to inform the user a face cannot be recognized. [CHAR LIMIT=25] -->
+ <string name="keyguard_face_failed">Can\u2019t recognize face</string>
+ <!-- Message shown to suggest using fingerprint sensor to authenticate after another biometric failed. [CHAR LIMIT=25] -->
+ <string name="keyguard_suggest_fingerprint">Use fingerprint instead</string>
<!-- Content description of the bluetooth icon when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_bluetooth_connected">Bluetooth connected.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 87f8a03..47dc5c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,9 +19,12 @@
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
+import static android.hardware.biometrics.BiometricSourceType.FACE;
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.getCurrentUser;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
@@ -428,9 +431,9 @@
if (info == null) {
// Use the current user owner information if enabled.
final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
- KeyguardUpdateMonitor.getCurrentUser());
+ getCurrentUser());
if (ownerInfoEnabled) {
- info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+ info = mLockPatternUtils.getOwnerInfo(getCurrentUser());
}
}
@@ -595,7 +598,7 @@
private void updateLockScreenLogoutView() {
final boolean shouldShowLogout = mKeyguardUpdateMonitor.isLogoutEnabled()
- && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
+ && getCurrentUser() != UserHandle.USER_SYSTEM;
if (shouldShowLogout) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_LOGOUT,
@@ -610,7 +613,7 @@
if (mFalsingManager.isFalseTap(LOW_PENALTY)) {
return;
}
- int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+ int currentUserId = getCurrentUser();
mDevicePolicyManager.logoutUser();
})
.build(),
@@ -767,7 +770,7 @@
mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
hideBiometricMessageDelayed(
mBiometricMessageFollowUp != null
- ? DEFAULT_HIDE_DELAY_MS * 2
+ ? IMPORTANT_MSG_MIN_DURATION * 2
: DEFAULT_HIDE_DELAY_MS
);
@@ -847,7 +850,7 @@
mTopIndicationView.setVisibility(GONE);
mTopIndicationView.setText(null);
mLockScreenIndicationView.setVisibility(View.VISIBLE);
- updateLockScreenIndications(animate, KeyguardUpdateMonitor.getCurrentUser());
+ updateLockScreenIndications(animate, getCurrentUser());
}
protected String computePowerIndication() {
@@ -915,7 +918,7 @@
public void showActionToUnlock() {
if (mDozing
&& !mKeyguardUpdateMonitor.getUserCanSkipBouncer(
- KeyguardUpdateMonitor.getCurrentUser())) {
+ getCurrentUser())) {
return;
}
@@ -928,7 +931,7 @@
}
} else {
final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(
- KeyguardUpdateMonitor.getCurrentUser());
+ getCurrentUser());
if (canSkipBouncer) {
final boolean faceAuthenticated = mKeyguardUpdateMonitor.getIsFaceAuthenticated();
final boolean udfpsSupported = mKeyguardUpdateMonitor.isUdfpsSupported();
@@ -1045,12 +1048,15 @@
return;
}
- boolean showActionToUnlock =
- msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
- if (biometricSourceType == BiometricSourceType.FACE
- && !showActionToUnlock
- && mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
- KeyguardUpdateMonitor.getCurrentUser())
+ final boolean faceAuthSoftError = biometricSourceType == FACE
+ && msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
+ final boolean faceAuthFailed = biometricSourceType == FACE
+ && msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed
+ final boolean isUnlockWithFingerprintPossible =
+ mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ getCurrentUser());
+ if (faceAuthSoftError
+ && isUnlockWithFingerprintPossible
&& !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
if (DEBUG) {
Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString
@@ -1061,8 +1067,16 @@
mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
mInitialTextColorState);
} else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
- showBiometricMessage(helpString);
- } else if (showActionToUnlock) {
+ if (faceAuthFailed && isUnlockWithFingerprintPossible) {
+ showBiometricMessage(
+ mContext.getString(R.string.keyguard_face_failed),
+ mContext.getString(R.string.keyguard_suggest_fingerprint)
+ );
+ } else {
+ showBiometricMessage(helpString);
+ }
+ } else if (faceAuthFailed) {
+ // show action to unlock
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
} else {
@@ -1080,17 +1094,17 @@
return;
}
- if (biometricSourceType == BiometricSourceType.FACE
+ if (biometricSourceType == FACE
&& msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
// suppress all face UNABLE_TO_PROCESS errors
if (DEBUG) {
Log.d(TAG, "skip showing FACE_ERROR_UNABLE_TO_PROCESS errString="
+ errString);
}
- } else if (biometricSourceType == BiometricSourceType.FACE
+ } else if (biometricSourceType == FACE
&& msgId == FaceManager.FACE_ERROR_TIMEOUT) {
if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
- KeyguardUpdateMonitor.getCurrentUser())) {
+ getCurrentUser())) {
// no message if fingerprint is also enrolled
if (DEBUG) {
Log.d(TAG, "skip showing FACE_ERROR_TIMEOUT due to co-ex logic");
@@ -1122,8 +1136,9 @@
BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
if (biometricSourceType == BiometricSourceType.FINGERPRINT)
return shouldSuppressFingerprintError(msgId, updateMonitor);
- if (biometricSourceType == BiometricSourceType.FACE)
+ if (biometricSourceType == FACE) {
return shouldSuppressFaceError(msgId, updateMonitor);
+ }
return false;
}
@@ -1152,7 +1167,7 @@
@Override
public void onTrustChanged(int userId) {
- if (KeyguardUpdateMonitor.getCurrentUser() != userId) {
+ if (getCurrentUser() != userId) {
return;
}
updateDeviceEntryIndication(false);
@@ -1172,7 +1187,7 @@
@Override
public void onBiometricRunningStateChanged(boolean running,
BiometricSourceType biometricSourceType) {
- if (running && biometricSourceType == BiometricSourceType.FACE) {
+ if (running && biometricSourceType == FACE) {
// Let's hide any previous messages when authentication starts, otherwise
// multiple auth attempts would overlap.
hideBiometricMessage();
@@ -1186,7 +1201,7 @@
super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
hideBiometricMessage();
- if (biometricSourceType == BiometricSourceType.FACE
+ if (biometricSourceType == FACE
&& !mKeyguardBypassController.canBypass()) {
showActionToUnlock();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 6afadcf..798f47d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -570,6 +570,33 @@
}
@Test
+ public void onBiometricHelp_coEx_faceFailure() {
+ 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 not recognized message
+ mController.getKeyguardCallback().onBiometricHelp(
+ KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
+ message,
+ BiometricSourceType.FACE);
+
+ // THEN show sequential messages such as: 'face not recognized' and
+ // 'try fingerprint instead'
+ verifyIndicationMessage(
+ INDICATION_TYPE_BIOMETRIC_MESSAGE,
+ mContext.getString(R.string.keyguard_face_failed));
+ verifyIndicationMessage(
+ INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+ mContext.getString(R.string.keyguard_suggest_fingerprint));
+ }
+
+ @Test
public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromError() {
createController();
String message = mContext.getString(R.string.keyguard_unlock);