Loading packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +45 −0 Original line number Diff line number Diff line Loading @@ -18,11 +18,16 @@ package com.android.keyguard; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.hardware.biometrics.BiometricSourceType; import android.os.SystemClock; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.util.Pair; import android.view.View; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.systemui.statusbar.policy.ConfigurationController; Loading @@ -39,6 +44,16 @@ import javax.inject.Inject; */ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> extends ViewController<T> { /** * Pair representing: * first - BiometricSource the currently displayed message is associated with. * second - Timestamp the biometric message came in uptimeMillis. * This Pair can be null if the message is not associated with a biometric. */ @Nullable private Pair<BiometricSourceType, Long> mMessageBiometricSource = null; private static final Long SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS = 3500L; /** * Delay before speaking an accessibility announcement. Used to prevent * lift-to-type from interrupting itself. Loading Loading @@ -149,12 +164,42 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> * Sets a message to the underlying text view. */ public void setMessage(CharSequence s, boolean animate) { setMessage(s, animate, null); } /** * Sets a message to the underlying text view. */ public void setMessage(CharSequence s, BiometricSourceType biometricSourceType) { setMessage(s, true, biometricSourceType); } private void setMessage( CharSequence s, boolean animate, BiometricSourceType biometricSourceType) { final long uptimeMillis = SystemClock.uptimeMillis(); if (skipShowingFaceMessage(biometricSourceType, uptimeMillis)) { Log.d("KeyguardMessageAreaController", "Skip showing face message \"" + s + "\""); return; } mMessageBiometricSource = new Pair<>(biometricSourceType, uptimeMillis); if (mView.isDisabled()) { return; } mView.setMessage(s, animate); } private boolean skipShowingFaceMessage( BiometricSourceType biometricSourceType, Long currentUptimeMillis ) { return mMessageBiometricSource != null && biometricSourceType == BiometricSourceType.FACE && mMessageBiometricSource.first == BiometricSourceType.FINGERPRINT && (currentUptimeMillis - mMessageBiometricSource.second) < SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS; } public void setMessage(int resId) { String message = resId != 0 ? mView.getResources().getString(resId) : null; setMessage(message); Loading packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt +21 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.keyguard.logging import android.hardware.biometrics.BiometricSourceType import com.android.systemui.biometrics.AuthRippleController import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController import com.android.systemui.log.LogBuffer Loading Loading @@ -117,6 +118,26 @@ constructor( ) } fun logDropNonFingerprintMessage( message: CharSequence, followUpMessage: CharSequence?, biometricSourceType: BiometricSourceType?, ) { buffer.log( KeyguardIndicationController.TAG, LogLevel.DEBUG, { str1 = message.toString() str2 = followUpMessage?.toString() str3 = biometricSourceType?.name }, { "droppingNonFingerprintMessage message=$str1 " + "followUpMessage:$str2 biometricSourceType:$str3" } ) } fun logUpdateBatteryIndication( powerIndication: String, pluggedIn: Boolean, Loading packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +110 −41 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.text.TextUtils; import android.text.format.Formatter; import android.util.Pair; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; Loading Loading @@ -187,6 +188,7 @@ public class KeyguardIndicationController { private CharSequence mTransientIndication; private CharSequence mBiometricMessage; private CharSequence mBiometricMessageFollowUp; private BiometricSourceType mBiometricMessageSource; protected ColorStateList mInitialTextColorState; private boolean mVisible; private boolean mOrganizationOwnedDevice; Loading @@ -206,7 +208,7 @@ public class KeyguardIndicationController { private int mBatteryLevel; private boolean mBatteryPresent = true; private long mChargingTimeRemaining; private String mBiometricErrorMessageToShowOnScreenOn; private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn; private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow; private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral; private boolean mInited; Loading @@ -225,15 +227,18 @@ public class KeyguardIndicationController { mIsActiveDreamLockscreenHosted = isLockscreenHosted; updateDeviceEntryIndication(false); }; private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @Override public void onScreenTurnedOn() { mHandler.removeMessages(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON); if (mBiometricErrorMessageToShowOnScreenOn != null) { String followUpMessage = mFaceLockedOutThisAuthSession ? faceLockedOutFollowupMessage() : null; showBiometricMessage(mBiometricErrorMessageToShowOnScreenOn, followUpMessage); showBiometricMessage( mBiometricErrorMessageToShowOnScreenOn.first, followUpMessage, mBiometricErrorMessageToShowOnScreenOn.second ); // We want to keep this message around in case the screen was off hideBiometricMessageDelayed(DEFAULT_HIDE_DELAY_MS); mBiometricErrorMessageToShowOnScreenOn = null; Loading Loading @@ -879,8 +884,35 @@ public class KeyguardIndicationController { updateTransient(); } private void showBiometricMessage(CharSequence biometricMessage) { showBiometricMessage(biometricMessage, null); private void showSuccessBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType ) { showBiometricMessage(biometricMessage, biometricMessageFollowUp, biometricSourceType, true); } private void showSuccessBiometricMessage(CharSequence biometricMessage, BiometricSourceType biometricSourceType) { showSuccessBiometricMessage(biometricMessage, null, biometricSourceType); } private void showBiometricMessage(CharSequence biometricMessage, BiometricSourceType biometricSourceType) { showBiometricMessage(biometricMessage, null, biometricSourceType, false); } private void showBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType ) { showBiometricMessage( biometricMessage, biometricMessageFollowUp, biometricSourceType, false ); } /** Loading @@ -889,15 +921,33 @@ public class KeyguardIndicationController { * by {@link KeyguardIndicationRotateTextViewController}, see class for rotating message * logic. */ private void showBiometricMessage(CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp) { private void showBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType, boolean isSuccessMessage ) { if (TextUtils.equals(biometricMessage, mBiometricMessage) && biometricSourceType == mBiometricMessageSource && TextUtils.equals(biometricMessageFollowUp, mBiometricMessageFollowUp)) { return; } if (!isSuccessMessage && mBiometricMessageSource == FINGERPRINT && biometricSourceType != FINGERPRINT) { // drop all non-fingerprint biometric messages if there's a fingerprint message showing mKeyguardLogger.logDropNonFingerprintMessage( biometricMessage, biometricMessageFollowUp, biometricSourceType ); return; } mBiometricMessage = biometricMessage; mBiometricMessageFollowUp = biometricMessageFollowUp; mBiometricMessageSource = biometricSourceType; mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK); hideBiometricMessageDelayed( Loading @@ -914,6 +964,7 @@ public class KeyguardIndicationController { if (mBiometricMessage != null || mBiometricMessageFollowUp != null) { mBiometricMessage = null; mBiometricMessageFollowUp = null; mBiometricMessageSource = null; mHideBiometricMessageHandler.cancel(); updateBiometricMessage(); } Loading Loading @@ -1085,7 +1136,8 @@ public class KeyguardIndicationController { } else { message = mContext.getString(R.string.keyguard_retry); } mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState); mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState, null); } } else { final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer( Loading @@ -1097,34 +1149,40 @@ public class KeyguardIndicationController { || mAccessibilityManager.isTouchExplorationEnabled(); if (udfpsSupported && faceAuthenticated) { // co-ex if (a11yEnabled) { showBiometricMessage( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), FACE ); } else { showBiometricMessage( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock_press) mContext.getString(R.string.keyguard_unlock_press), FACE ); } } else if (faceAuthenticated) { // face-only showBiometricMessage( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), FACE ); } else if (udfpsSupported) { // udfps-only if (a11yEnabled) { showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); showSuccessBiometricMessage( mContext.getString(R.string.keyguard_unlock), null ); } else { showBiometricMessage(mContext.getString( R.string.keyguard_unlock_press)); showSuccessBiometricMessage(mContext.getString( R.string.keyguard_unlock_press), null); } } else { // no security or unlocked by a trust agent showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); showSuccessBiometricMessage(mContext.getString(R.string.keyguard_unlock), null); } } else { // suggest swiping up for the primary authentication bouncer showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); showBiometricMessage(mContext.getString(R.string.keyguard_unlock), null); } } } Loading Loading @@ -1245,49 +1303,55 @@ public class KeyguardIndicationController { mBouncerMessageInteractor.setFaceAcquisitionMessage(helpString); } mStatusBarKeyguardViewManager.setKeyguardMessage(helpString, mInitialTextColorState); mInitialTextColorState, biometricSourceType); } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) { showBiometricMessage( helpString, mContext.getString(R.string.keyguard_suggest_fingerprint) mContext.getString(R.string.keyguard_suggest_fingerprint), biometricSourceType ); } else if (faceAuthFailed && isUnlockWithFingerprintPossible) { showBiometricMessage( mContext.getString(R.string.keyguard_face_failed), mContext.getString(R.string.keyguard_suggest_fingerprint) mContext.getString(R.string.keyguard_suggest_fingerprint), biometricSourceType ); } else if (fpAuthFailed && mKeyguardUpdateMonitor.isCurrentUserUnlockedWithFace()) { // 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( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), null ); } else if (fpAuthFailed && mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser())) { showBiometricMessage( showSuccessBiometricMessage( getTrustGrantedIndication(), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), null ); } else if (faceAuthUnavailable) { showBiometricMessage( helpString, isUnlockWithFingerprintPossible ? mContext.getString(R.string.keyguard_suggest_fingerprint) : mContext.getString(R.string.keyguard_unlock) : mContext.getString(R.string.keyguard_unlock), biometricSourceType ); } else { showBiometricMessage(helpString); showBiometricMessage(helpString, biometricSourceType); } } else if (faceAuthFailed) { // show action to unlock mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK), TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); } else { mBiometricErrorMessageToShowOnScreenOn = helpString; mBiometricErrorMessageToShowOnScreenOn = new Pair<>(helpString, biometricSourceType); mHandler.sendMessageDelayed( mHandler.obtainMessage(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON), 1000); Loading Loading @@ -1333,7 +1397,7 @@ public class KeyguardIndicationController { } else if (mIndicationHelper.isFaceLockoutErrorMsg(msgId)) { handleFaceLockoutError(errString); } else { showErrorMessageNowOrLater(errString, null); showErrorMessageNowOrLater(errString, null, FACE); } } Loading @@ -1343,7 +1407,7 @@ public class KeyguardIndicationController { msgId, errString); } else { showErrorMessageNowOrLater(errString, null); showErrorMessageNowOrLater(errString, null, FINGERPRINT); } } Loading Loading @@ -1371,7 +1435,7 @@ public class KeyguardIndicationController { @Override public void onTrustAgentErrorMessage(CharSequence message) { showBiometricMessage(message); showBiometricMessage(message, null); } @Override Loading Loading @@ -1459,12 +1523,13 @@ public class KeyguardIndicationController { // had too many unsuccessful attempts. if (!mFaceLockedOutThisAuthSession) { mFaceLockedOutThisAuthSession = true; showErrorMessageNowOrLater(errString, followupMessage); showErrorMessageNowOrLater(errString, followupMessage, FACE); } else if (!mAuthController.isUdfpsFingerDown()) { // On subsequent lockouts, we show a more generic locked out message. showErrorMessageNowOrLater( mContext.getString(R.string.keyguard_face_unlock_unavailable), followupMessage); followupMessage, FACE); } } Loading @@ -1484,7 +1549,8 @@ public class KeyguardIndicationController { && !mStatusBarKeyguardViewManager.isBouncerShowing()) { showBiometricMessage( deferredFaceMessage, mContext.getString(R.string.keyguard_suggest_fingerprint) mContext.getString(R.string.keyguard_suggest_fingerprint), FACE ); } else { // otherwise, don't show any message Loading @@ -1496,7 +1562,8 @@ public class KeyguardIndicationController { // user to manually retry. showBiometricMessage( deferredFaceMessage, mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), FACE ); } else { // Face-only Loading @@ -1510,13 +1577,15 @@ public class KeyguardIndicationController { getCurrentUser()) && mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed(); } private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg) { private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg, BiometricSourceType biometricSourceType) { if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState); mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState, biometricSourceType); } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { showBiometricMessage(errString, followUpMsg); showBiometricMessage(errString, followUpMsg, biometricSourceType); } else { mBiometricErrorMessageToShowOnScreenOn = errString; mBiometricErrorMessageToShowOnScreenOn = new Pair<>(errString, biometricSourceType); } } Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +4 −3 Original line number Diff line number Diff line Loading @@ -781,7 +781,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } updateAlternateBouncerShowing(mAlternateBouncerInteractor.show()); setKeyguardMessage(message, null); setKeyguardMessage(message, null, null); return; } Loading Loading @@ -1444,11 +1444,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** Display security message to relevant KeyguardMessageArea. */ public void setKeyguardMessage(String message, ColorStateList colorState) { public void setKeyguardMessage(String message, ColorStateList colorState, BiometricSourceType biometricSourceType) { if (mAlternateBouncerInteractor.isVisibleState()) { if (mKeyguardMessageAreaController != null) { DeviceEntryUdfpsRefactor.assertInLegacyMode(); mKeyguardMessageAreaController.setMessage(message); mKeyguardMessageAreaController.setMessage(message, biometricSourceType); } } else { mPrimaryBouncerInteractor.showMessage(message, colorState); Loading packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,14 @@ package com.android.keyguard; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.hardware.biometrics.BiometricSourceType; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading Loading @@ -119,4 +122,51 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase { when(mKeyguardMessageArea.getText()).thenReturn(msg); assertThat(mMessageAreaController.getMessage()).isEqualTo(msg); } @Test public void testFingerprintMessageUpdate() { String msg = "fpMessage"; mMessageAreaController.setMessage( msg, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(msg, /* animate= */ true); String msg2 = "fpMessage2"; mMessageAreaController.setMessage( msg2, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(msg2, /* animate= */ true); } @Test public void testFaceMessageDroppedWhileFingerprintMessageShowing() { String fpMsg = "fpMessage"; mMessageAreaController.setMessage( fpMsg, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean()); String faceMessage = "faceMessage"; mMessageAreaController.setMessage( faceMessage, BiometricSourceType.FACE ); verify(mKeyguardMessageArea, never()) .setMessage(eq(faceMessage), /* animate= */ anyBoolean()); } @Test public void testGenericMessageShowsAfterFingerprintMessageShowing() { String fpMsg = "fpMessage"; mMessageAreaController.setMessage( fpMsg, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean()); String genericMessage = "genericMessage"; mMessageAreaController.setMessage( genericMessage, null ); verify(mKeyguardMessageArea) .setMessage(eq(genericMessage), /* animate= */ anyBoolean()); } } Loading
packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +45 −0 Original line number Diff line number Diff line Loading @@ -18,11 +18,16 @@ package com.android.keyguard; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.hardware.biometrics.BiometricSourceType; import android.os.SystemClock; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.util.Pair; import android.view.View; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.systemui.statusbar.policy.ConfigurationController; Loading @@ -39,6 +44,16 @@ import javax.inject.Inject; */ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> extends ViewController<T> { /** * Pair representing: * first - BiometricSource the currently displayed message is associated with. * second - Timestamp the biometric message came in uptimeMillis. * This Pair can be null if the message is not associated with a biometric. */ @Nullable private Pair<BiometricSourceType, Long> mMessageBiometricSource = null; private static final Long SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS = 3500L; /** * Delay before speaking an accessibility announcement. Used to prevent * lift-to-type from interrupting itself. Loading Loading @@ -149,12 +164,42 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> * Sets a message to the underlying text view. */ public void setMessage(CharSequence s, boolean animate) { setMessage(s, animate, null); } /** * Sets a message to the underlying text view. */ public void setMessage(CharSequence s, BiometricSourceType biometricSourceType) { setMessage(s, true, biometricSourceType); } private void setMessage( CharSequence s, boolean animate, BiometricSourceType biometricSourceType) { final long uptimeMillis = SystemClock.uptimeMillis(); if (skipShowingFaceMessage(biometricSourceType, uptimeMillis)) { Log.d("KeyguardMessageAreaController", "Skip showing face message \"" + s + "\""); return; } mMessageBiometricSource = new Pair<>(biometricSourceType, uptimeMillis); if (mView.isDisabled()) { return; } mView.setMessage(s, animate); } private boolean skipShowingFaceMessage( BiometricSourceType biometricSourceType, Long currentUptimeMillis ) { return mMessageBiometricSource != null && biometricSourceType == BiometricSourceType.FACE && mMessageBiometricSource.first == BiometricSourceType.FINGERPRINT && (currentUptimeMillis - mMessageBiometricSource.second) < SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS; } public void setMessage(int resId) { String message = resId != 0 ? mView.getResources().getString(resId) : null; setMessage(message); Loading
packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt +21 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.keyguard.logging import android.hardware.biometrics.BiometricSourceType import com.android.systemui.biometrics.AuthRippleController import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController import com.android.systemui.log.LogBuffer Loading Loading @@ -117,6 +118,26 @@ constructor( ) } fun logDropNonFingerprintMessage( message: CharSequence, followUpMessage: CharSequence?, biometricSourceType: BiometricSourceType?, ) { buffer.log( KeyguardIndicationController.TAG, LogLevel.DEBUG, { str1 = message.toString() str2 = followUpMessage?.toString() str3 = biometricSourceType?.name }, { "droppingNonFingerprintMessage message=$str1 " + "followUpMessage:$str2 biometricSourceType:$str3" } ) } fun logUpdateBatteryIndication( powerIndication: String, pluggedIn: Boolean, Loading
packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +110 −41 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.text.TextUtils; import android.text.format.Formatter; import android.util.Pair; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; Loading Loading @@ -187,6 +188,7 @@ public class KeyguardIndicationController { private CharSequence mTransientIndication; private CharSequence mBiometricMessage; private CharSequence mBiometricMessageFollowUp; private BiometricSourceType mBiometricMessageSource; protected ColorStateList mInitialTextColorState; private boolean mVisible; private boolean mOrganizationOwnedDevice; Loading @@ -206,7 +208,7 @@ public class KeyguardIndicationController { private int mBatteryLevel; private boolean mBatteryPresent = true; private long mChargingTimeRemaining; private String mBiometricErrorMessageToShowOnScreenOn; private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn; private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow; private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral; private boolean mInited; Loading @@ -225,15 +227,18 @@ public class KeyguardIndicationController { mIsActiveDreamLockscreenHosted = isLockscreenHosted; updateDeviceEntryIndication(false); }; private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @Override public void onScreenTurnedOn() { mHandler.removeMessages(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON); if (mBiometricErrorMessageToShowOnScreenOn != null) { String followUpMessage = mFaceLockedOutThisAuthSession ? faceLockedOutFollowupMessage() : null; showBiometricMessage(mBiometricErrorMessageToShowOnScreenOn, followUpMessage); showBiometricMessage( mBiometricErrorMessageToShowOnScreenOn.first, followUpMessage, mBiometricErrorMessageToShowOnScreenOn.second ); // We want to keep this message around in case the screen was off hideBiometricMessageDelayed(DEFAULT_HIDE_DELAY_MS); mBiometricErrorMessageToShowOnScreenOn = null; Loading Loading @@ -879,8 +884,35 @@ public class KeyguardIndicationController { updateTransient(); } private void showBiometricMessage(CharSequence biometricMessage) { showBiometricMessage(biometricMessage, null); private void showSuccessBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType ) { showBiometricMessage(biometricMessage, biometricMessageFollowUp, biometricSourceType, true); } private void showSuccessBiometricMessage(CharSequence biometricMessage, BiometricSourceType biometricSourceType) { showSuccessBiometricMessage(biometricMessage, null, biometricSourceType); } private void showBiometricMessage(CharSequence biometricMessage, BiometricSourceType biometricSourceType) { showBiometricMessage(biometricMessage, null, biometricSourceType, false); } private void showBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType ) { showBiometricMessage( biometricMessage, biometricMessageFollowUp, biometricSourceType, false ); } /** Loading @@ -889,15 +921,33 @@ public class KeyguardIndicationController { * by {@link KeyguardIndicationRotateTextViewController}, see class for rotating message * logic. */ private void showBiometricMessage(CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp) { private void showBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType, boolean isSuccessMessage ) { if (TextUtils.equals(biometricMessage, mBiometricMessage) && biometricSourceType == mBiometricMessageSource && TextUtils.equals(biometricMessageFollowUp, mBiometricMessageFollowUp)) { return; } if (!isSuccessMessage && mBiometricMessageSource == FINGERPRINT && biometricSourceType != FINGERPRINT) { // drop all non-fingerprint biometric messages if there's a fingerprint message showing mKeyguardLogger.logDropNonFingerprintMessage( biometricMessage, biometricMessageFollowUp, biometricSourceType ); return; } mBiometricMessage = biometricMessage; mBiometricMessageFollowUp = biometricMessageFollowUp; mBiometricMessageSource = biometricSourceType; mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK); hideBiometricMessageDelayed( Loading @@ -914,6 +964,7 @@ public class KeyguardIndicationController { if (mBiometricMessage != null || mBiometricMessageFollowUp != null) { mBiometricMessage = null; mBiometricMessageFollowUp = null; mBiometricMessageSource = null; mHideBiometricMessageHandler.cancel(); updateBiometricMessage(); } Loading Loading @@ -1085,7 +1136,8 @@ public class KeyguardIndicationController { } else { message = mContext.getString(R.string.keyguard_retry); } mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState); mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState, null); } } else { final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer( Loading @@ -1097,34 +1149,40 @@ public class KeyguardIndicationController { || mAccessibilityManager.isTouchExplorationEnabled(); if (udfpsSupported && faceAuthenticated) { // co-ex if (a11yEnabled) { showBiometricMessage( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), FACE ); } else { showBiometricMessage( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock_press) mContext.getString(R.string.keyguard_unlock_press), FACE ); } } else if (faceAuthenticated) { // face-only showBiometricMessage( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), FACE ); } else if (udfpsSupported) { // udfps-only if (a11yEnabled) { showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); showSuccessBiometricMessage( mContext.getString(R.string.keyguard_unlock), null ); } else { showBiometricMessage(mContext.getString( R.string.keyguard_unlock_press)); showSuccessBiometricMessage(mContext.getString( R.string.keyguard_unlock_press), null); } } else { // no security or unlocked by a trust agent showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); showSuccessBiometricMessage(mContext.getString(R.string.keyguard_unlock), null); } } else { // suggest swiping up for the primary authentication bouncer showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); showBiometricMessage(mContext.getString(R.string.keyguard_unlock), null); } } } Loading Loading @@ -1245,49 +1303,55 @@ public class KeyguardIndicationController { mBouncerMessageInteractor.setFaceAcquisitionMessage(helpString); } mStatusBarKeyguardViewManager.setKeyguardMessage(helpString, mInitialTextColorState); mInitialTextColorState, biometricSourceType); } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) { showBiometricMessage( helpString, mContext.getString(R.string.keyguard_suggest_fingerprint) mContext.getString(R.string.keyguard_suggest_fingerprint), biometricSourceType ); } else if (faceAuthFailed && isUnlockWithFingerprintPossible) { showBiometricMessage( mContext.getString(R.string.keyguard_face_failed), mContext.getString(R.string.keyguard_suggest_fingerprint) mContext.getString(R.string.keyguard_suggest_fingerprint), biometricSourceType ); } else if (fpAuthFailed && mKeyguardUpdateMonitor.isCurrentUserUnlockedWithFace()) { // 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( showSuccessBiometricMessage( mContext.getString(R.string.keyguard_face_successful_unlock), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), null ); } else if (fpAuthFailed && mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser())) { showBiometricMessage( showSuccessBiometricMessage( getTrustGrantedIndication(), mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), null ); } else if (faceAuthUnavailable) { showBiometricMessage( helpString, isUnlockWithFingerprintPossible ? mContext.getString(R.string.keyguard_suggest_fingerprint) : mContext.getString(R.string.keyguard_unlock) : mContext.getString(R.string.keyguard_unlock), biometricSourceType ); } else { showBiometricMessage(helpString); showBiometricMessage(helpString, biometricSourceType); } } else if (faceAuthFailed) { // show action to unlock mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK), TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); } else { mBiometricErrorMessageToShowOnScreenOn = helpString; mBiometricErrorMessageToShowOnScreenOn = new Pair<>(helpString, biometricSourceType); mHandler.sendMessageDelayed( mHandler.obtainMessage(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON), 1000); Loading Loading @@ -1333,7 +1397,7 @@ public class KeyguardIndicationController { } else if (mIndicationHelper.isFaceLockoutErrorMsg(msgId)) { handleFaceLockoutError(errString); } else { showErrorMessageNowOrLater(errString, null); showErrorMessageNowOrLater(errString, null, FACE); } } Loading @@ -1343,7 +1407,7 @@ public class KeyguardIndicationController { msgId, errString); } else { showErrorMessageNowOrLater(errString, null); showErrorMessageNowOrLater(errString, null, FINGERPRINT); } } Loading Loading @@ -1371,7 +1435,7 @@ public class KeyguardIndicationController { @Override public void onTrustAgentErrorMessage(CharSequence message) { showBiometricMessage(message); showBiometricMessage(message, null); } @Override Loading Loading @@ -1459,12 +1523,13 @@ public class KeyguardIndicationController { // had too many unsuccessful attempts. if (!mFaceLockedOutThisAuthSession) { mFaceLockedOutThisAuthSession = true; showErrorMessageNowOrLater(errString, followupMessage); showErrorMessageNowOrLater(errString, followupMessage, FACE); } else if (!mAuthController.isUdfpsFingerDown()) { // On subsequent lockouts, we show a more generic locked out message. showErrorMessageNowOrLater( mContext.getString(R.string.keyguard_face_unlock_unavailable), followupMessage); followupMessage, FACE); } } Loading @@ -1484,7 +1549,8 @@ public class KeyguardIndicationController { && !mStatusBarKeyguardViewManager.isBouncerShowing()) { showBiometricMessage( deferredFaceMessage, mContext.getString(R.string.keyguard_suggest_fingerprint) mContext.getString(R.string.keyguard_suggest_fingerprint), FACE ); } else { // otherwise, don't show any message Loading @@ -1496,7 +1562,8 @@ public class KeyguardIndicationController { // user to manually retry. showBiometricMessage( deferredFaceMessage, mContext.getString(R.string.keyguard_unlock) mContext.getString(R.string.keyguard_unlock), FACE ); } else { // Face-only Loading @@ -1510,13 +1577,15 @@ public class KeyguardIndicationController { getCurrentUser()) && mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed(); } private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg) { private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg, BiometricSourceType biometricSourceType) { if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState); mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState, biometricSourceType); } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { showBiometricMessage(errString, followUpMsg); showBiometricMessage(errString, followUpMsg, biometricSourceType); } else { mBiometricErrorMessageToShowOnScreenOn = errString; mBiometricErrorMessageToShowOnScreenOn = new Pair<>(errString, biometricSourceType); } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +4 −3 Original line number Diff line number Diff line Loading @@ -781,7 +781,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } updateAlternateBouncerShowing(mAlternateBouncerInteractor.show()); setKeyguardMessage(message, null); setKeyguardMessage(message, null, null); return; } Loading Loading @@ -1444,11 +1444,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** Display security message to relevant KeyguardMessageArea. */ public void setKeyguardMessage(String message, ColorStateList colorState) { public void setKeyguardMessage(String message, ColorStateList colorState, BiometricSourceType biometricSourceType) { if (mAlternateBouncerInteractor.isVisibleState()) { if (mKeyguardMessageAreaController != null) { DeviceEntryUdfpsRefactor.assertInLegacyMode(); mKeyguardMessageAreaController.setMessage(message); mKeyguardMessageAreaController.setMessage(message, biometricSourceType); } } else { mPrimaryBouncerInteractor.showMessage(message, colorState); Loading
packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,14 @@ package com.android.keyguard; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.hardware.biometrics.BiometricSourceType; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading Loading @@ -119,4 +122,51 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase { when(mKeyguardMessageArea.getText()).thenReturn(msg); assertThat(mMessageAreaController.getMessage()).isEqualTo(msg); } @Test public void testFingerprintMessageUpdate() { String msg = "fpMessage"; mMessageAreaController.setMessage( msg, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(msg, /* animate= */ true); String msg2 = "fpMessage2"; mMessageAreaController.setMessage( msg2, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(msg2, /* animate= */ true); } @Test public void testFaceMessageDroppedWhileFingerprintMessageShowing() { String fpMsg = "fpMessage"; mMessageAreaController.setMessage( fpMsg, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean()); String faceMessage = "faceMessage"; mMessageAreaController.setMessage( faceMessage, BiometricSourceType.FACE ); verify(mKeyguardMessageArea, never()) .setMessage(eq(faceMessage), /* animate= */ anyBoolean()); } @Test public void testGenericMessageShowsAfterFingerprintMessageShowing() { String fpMsg = "fpMessage"; mMessageAreaController.setMessage( fpMsg, BiometricSourceType.FINGERPRINT ); verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean()); String genericMessage = "genericMessage"; mMessageAreaController.setMessage( genericMessage, null ); verify(mKeyguardMessageArea) .setMessage(eq(genericMessage), /* animate= */ anyBoolean()); } }