From 8548493bdf5f1685fe30e7331d14aaa8c358b232 Mon Sep 17 00:00:00 2001 From: Beverly Date: Mon, 16 May 2022 18:43:53 +0000 Subject: [PATCH] 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 --- packages/SystemUI/res/values/config.xml | 6 ++ .../keyguard/KeyguardUpdateMonitor.java | 1 - .../KeyguardIndicationController.java | 53 +++++++++-- .../KeyguardIndicationControllerTest.java | 92 +++++++++++++++++++ 4 files changed, 144 insertions(+), 8 deletions(-) diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index c8fff39cc8e5e..b7d517f042576 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -611,6 +611,12 @@ 2 - Override the setting to never bypass keyguard --> 0 + + + + + false diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 98f3d946256fb..855fc241800be 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -275,7 +275,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab HashMap mSimDatas = new HashMap<>(); HashMap mServiceStates = new HashMap(); - private int mRingMode; private int mPhoneState; private boolean mKeyguardIsVisible; private boolean mCredentialAttempted; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 6602f99470517..0c89340ec3969 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -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 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 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 d394d7dcebbe5..2be5536f1c3b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -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 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 messages) { + verify(mRotateTextViewController, times(messages.size())).updateIndication(eq(type), + mKeyguardIndicationCaptor.capture(), anyBoolean()); + List 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());