Update vis of face acquisition + err messages
When fingerprint is also enrolled, don't surface
FACE_TIMEOUT errors or face acquisition messages.
This CL also adds the ability to override the face
acquisition messages that can show when fp is also
enrolled. This can be done via adb. For example,
the following command would enable
FACE_ACQUIRED_MOUTH_COVERING_DETECTED and
FACE_ACQUIRED_DARK_GLASSES_DETECTED
adb shell settings put global coex_face_help_msgs "26\|25"
This override is for temporary teamfooding and should be removed
before release.
Test: manual
Test: atest KeyguardIndicationControllerTest
Bug: 231733975
Change-Id: I1fb569adcf91576f89aa1fb068db8bdd030ea645
This commit is contained in:
@@ -611,6 +611,12 @@
|
||||
2 - Override the setting to never bypass keyguard -->
|
||||
<integer name="config_face_unlock_bypass_override">0</integer>
|
||||
|
||||
<!-- Which face help messages to surface when fingerprint is also enrolled.
|
||||
Message ids correspond with the acquired ids in BiometricFaceConstants -->
|
||||
<integer-array name="config_face_help_msgs_when_fingerprint_enrolled">
|
||||
<!-- for example: <item>26</item> for FACE_ACQUIRED_MOUTH_COVERING_DETECTED -->
|
||||
</integer-array>
|
||||
|
||||
<!-- Whether the communal service should be enabled -->
|
||||
<bool name="config_communalServiceEnabled">false</bool>
|
||||
|
||||
|
||||
@@ -275,7 +275,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
|
||||
HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>();
|
||||
|
||||
private int mRingMode;
|
||||
private int mPhoneState;
|
||||
private boolean mKeyguardIsVisible;
|
||||
private boolean mCredentialAttempted;
|
||||
|
||||
@@ -49,12 +49,14 @@ import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
@@ -92,6 +94,8 @@ import com.android.systemui.util.wakelock.WakeLock;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -112,12 +116,12 @@ public class KeyguardIndicationController {
|
||||
|
||||
private static final String TAG = "KeyguardIndication";
|
||||
private static final boolean DEBUG_CHARGING_SPEED = false;
|
||||
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
|
||||
|
||||
private static final int MSG_HIDE_TRANSIENT = 1;
|
||||
private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
|
||||
private static final int MSG_HIDE_BIOMETRIC_MESSAGE = 3;
|
||||
private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
|
||||
private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
|
||||
|
||||
private final Context mContext;
|
||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
||||
@@ -166,6 +170,7 @@ public class KeyguardIndicationController {
|
||||
private boolean mBatteryPresent = true;
|
||||
private long mChargingTimeRemaining;
|
||||
private String mMessageToShowOnScreenOn;
|
||||
private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
|
||||
private boolean mInited;
|
||||
|
||||
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
|
||||
@@ -234,6 +239,22 @@ public class KeyguardIndicationController {
|
||||
mScreenLifecycle = screenLifecycle;
|
||||
mScreenLifecycle.addObserver(mScreenObserver);
|
||||
|
||||
mCoExFaceHelpMsgIdsToShow = new HashSet<>();
|
||||
final String msgsToShowOverride = Settings.Global.getString(mContext.getContentResolver(),
|
||||
"coex_face_help_msgs"); // TODO: remove after UX testing b/231733975
|
||||
if (msgsToShowOverride != null) {
|
||||
final String[] msgIds = msgsToShowOverride.split("\\|");
|
||||
for (String msgId : msgIds) {
|
||||
mCoExFaceHelpMsgIdsToShow.add(Integer.parseInt(msgId));
|
||||
}
|
||||
} else {
|
||||
int[] msgIds = context.getResources().getIntArray(
|
||||
com.android.systemui.R.array.config_face_help_msgs_when_fingerprint_enrolled);
|
||||
for (int msgId : msgIds) {
|
||||
mCoExFaceHelpMsgIdsToShow.add(msgId);
|
||||
}
|
||||
}
|
||||
|
||||
mHandler = new Handler(mainLooper) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
@@ -924,6 +945,7 @@ public class KeyguardIndicationController {
|
||||
mTopIndicationView == null ? null : mTopIndicationView.getText()));
|
||||
pw.println(" computePowerIndication(): " + computePowerIndication());
|
||||
pw.println(" trustGrantedIndication: " + getTrustGrantedIndication());
|
||||
pw.println(" mCoExFaceHelpMsgIdsToShow=" + mCoExFaceHelpMsgIdsToShow);
|
||||
mRotateTextViewController.dump(pw, args);
|
||||
}
|
||||
|
||||
@@ -982,9 +1004,20 @@ public class KeyguardIndicationController {
|
||||
.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean showActionToUnlock =
|
||||
msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
|
||||
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
|
||||
if (biometricSourceType == BiometricSourceType.FACE
|
||||
&& !showActionToUnlock
|
||||
&& mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
|
||||
KeyguardUpdateMonitor.getCurrentUser())
|
||||
&& !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString
|
||||
+ ", due to co-ex logic");
|
||||
}
|
||||
return;
|
||||
} else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
|
||||
mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
|
||||
mInitialTextColorState);
|
||||
} else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
|
||||
@@ -1001,14 +1034,20 @@ public class KeyguardIndicationController {
|
||||
if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
|
||||
if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
|
||||
KeyguardUpdateMonitor.getCurrentUser())) {
|
||||
// no message if fingerprint is also enrolled
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "skip showing FACE_ERROR_TIMEOUT due to co-ex logic");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// The face timeout message is not very actionable, let's ask the user to
|
||||
// manually retry.
|
||||
if (!mStatusBarKeyguardViewManager.isBouncerShowing()
|
||||
&& mKeyguardUpdateMonitor.isUdfpsEnrolled()
|
||||
&& mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
|
||||
showFaceFailedTryFingerprintMsg(msgId, errString);
|
||||
} else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
|
||||
if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
|
||||
mStatusBarKeyguardViewManager.showBouncerMessage(
|
||||
mContext.getResources().getString(R.string.keyguard_try_fingerprint),
|
||||
mInitialTextColorState
|
||||
|
||||
@@ -45,6 +45,7 @@ import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -59,6 +60,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.Color;
|
||||
import android.hardware.biometrics.BiometricFaceConstants;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
@@ -106,6 +108,9 @@ import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@@ -577,6 +582,80 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
verify(mStatusBarKeyguardViewManager).showBouncerMessage(eq(message), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void faceErrorTimeout_whenFingerprintEnrolled_doesNotShowMessage() {
|
||||
createController();
|
||||
when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
|
||||
0)).thenReturn(true);
|
||||
String message = "A message";
|
||||
|
||||
mController.setVisible(true);
|
||||
mController.getKeyguardCallback().onBiometricError(
|
||||
FaceManager.FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
|
||||
verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doNotSendFaceHelpMessages_fingerprintEnrolled() {
|
||||
createController();
|
||||
|
||||
// GIVEN fingerprint enrolled
|
||||
when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
|
||||
0)).thenReturn(true);
|
||||
|
||||
// WHEN help messages received
|
||||
final String helpString = "helpString";
|
||||
final int[] msgIds = new int[]{
|
||||
BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
|
||||
};
|
||||
for (int msgId : msgIds) {
|
||||
mKeyguardUpdateMonitorCallback.onBiometricHelp(
|
||||
msgId, helpString + msgId, BiometricSourceType.FACE);
|
||||
}
|
||||
|
||||
// THEN no messages shown
|
||||
verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendAllFaceHelpMessages_fingerprintNotEnrolled() {
|
||||
createController();
|
||||
|
||||
// GIVEN fingerprint NOT enrolled
|
||||
when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
|
||||
0)).thenReturn(false);
|
||||
|
||||
// WHEN help messages received
|
||||
final Set<CharSequence> helpStrings = new HashSet<>();
|
||||
final String helpString = "helpString";
|
||||
final int[] msgIds = new int[]{
|
||||
BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
|
||||
};
|
||||
for (int msgId : msgIds) {
|
||||
final String numberedHelpString = helpString + msgId;
|
||||
mKeyguardUpdateMonitorCallback.onBiometricHelp(
|
||||
msgId, numberedHelpString, BiometricSourceType.FACE);
|
||||
helpStrings.add(numberedHelpString);
|
||||
}
|
||||
|
||||
// THEN message shown for each call
|
||||
verifyIndicationMessages(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpStrings);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateMonitor_listenerUpdatesIndication() {
|
||||
createController();
|
||||
@@ -850,6 +929,19 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
mBroadcastReceiver.onReceive(mContext, new Intent());
|
||||
}
|
||||
|
||||
private void verifyIndicationMessages(int type, Set<CharSequence> messages) {
|
||||
verify(mRotateTextViewController, times(messages.size())).updateIndication(eq(type),
|
||||
mKeyguardIndicationCaptor.capture(), anyBoolean());
|
||||
List<KeyguardIndication> kis = mKeyguardIndicationCaptor.getAllValues();
|
||||
|
||||
for (KeyguardIndication ki : kis) {
|
||||
final CharSequence msg = ki.getMessage();
|
||||
assertTrue(messages.contains(msg)); // check message is shown
|
||||
messages.remove(msg);
|
||||
}
|
||||
assertThat(messages.size()).isEqualTo(0); // check that all messages accounted for (removed)
|
||||
}
|
||||
|
||||
private void verifyIndicationMessage(int type, String message) {
|
||||
verify(mRotateTextViewController).updateIndication(eq(type),
|
||||
mKeyguardIndicationCaptor.capture(), anyBoolean());
|
||||
|
||||
Reference in New Issue
Block a user