diff options
4 files changed, 144 insertions, 8 deletions
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index e62a398cd8bb..85ff5f0009e3 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -614,6 +614,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> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 98f3d946256f..855fc241800b 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<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; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 6602f9947051..0c89340ec396 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<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 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 d394d7dcebbe..2be5536f1c3b 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) @@ -578,6 +583,80 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { } @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(); String restingIndication = "Resting indication"; @@ -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()); |