summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2022-09-08 15:34:15 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-09-08 15:34:15 +0000
commita12fe48a22b73e7927e769a27543bc8de54e6979 (patch)
treecf137256f24bade07c1dea7dd18163f52b1ca1db
parente04e312e984a3678ee8369d99b7191f49f9b6bb6 (diff)
parent59ce3eac823e3fdf7c7f44861dbf81554b5e56e6 (diff)
Merge changes from topic "too_dark_face_acquisition_message_enable" into tm-qpr-dev
* changes: Show low light soft-error on FACE_TIMEOUT [Co-ex] Show 'too_dark' face acquired messages
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java104
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt147
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java72
6 files changed, 378 insertions, 41 deletions
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index aad32b118b8f..f0ba5ff2ecf4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1804,7 +1804,7 @@
<!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
<string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
<!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
- <string name="face_acquired_too_dark">Try brighter lighting</string>
+ <string name="face_acquired_too_dark">Not enough light</string>
<!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
<string name="face_acquired_too_close">Move phone farther away</string>
<!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ec22c609b0b9..ae9ebbacea05 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -617,8 +617,9 @@
<!-- 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">
- <item>25</item>
- <item>26</item>
+ <item>3</item> <!-- TOO_DARK -->
+ <item>25</item> <!-- DARK_GLASSES -->
+ <item>26</item> <!-- MOUTH_COVERING_DETECTED -->
</integer-array>
<!-- Whether the communal service should be enabled -->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
new file mode 100644
index 000000000000..f2d8aaa30f21
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+/**
+ * Provides whether an acquired error message should be shown immediately when its received (see
+ * [shouldDefer]) or should be shown when the biometric error is received [getDeferredMessage].
+ * @property excludedMessages messages that are excluded from counts
+ * @property messagesToDefer messages that shouldn't show immediately when received, but may be
+ * shown later if the message is the most frequent message processed and meets [THRESHOLD]
+ * percentage of all messages (excluding [excludedMessages])
+ */
+class BiometricMessageDeferral(
+ private val excludedMessages: Set<Int>,
+ private val messagesToDefer: Set<Int>
+) {
+ private val msgCounts: MutableMap<Int, Int> = HashMap() // msgId => frequency of msg
+ private val msgIdToCharSequence: MutableMap<Int, CharSequence> = HashMap() // msgId => message
+ private var totalRelevantMessages = 0
+ private var mostFrequentMsgIdToDefer: Int? = null
+
+ /** Reset all saved counts. */
+ fun reset() {
+ totalRelevantMessages = 0
+ msgCounts.clear()
+ msgIdToCharSequence.clear()
+ }
+
+ /** Whether the given message should be deferred instead of being shown immediately. */
+ fun shouldDefer(acquiredMsgId: Int): Boolean {
+ return messagesToDefer.contains(acquiredMsgId)
+ }
+
+ /**
+ * Adds the acquiredMsgId to the counts if it's not in [excludedMessages]. We still count
+ * messages that shouldn't be deferred in these counts.
+ */
+ fun processMessage(acquiredMsgId: Int, helpString: CharSequence) {
+ if (excludedMessages.contains(acquiredMsgId)) {
+ return
+ }
+
+ totalRelevantMessages++
+ msgIdToCharSequence[acquiredMsgId] = helpString
+
+ val newAcquiredMsgCount = msgCounts.getOrDefault(acquiredMsgId, 0) + 1
+ msgCounts[acquiredMsgId] = newAcquiredMsgCount
+ if (
+ messagesToDefer.contains(acquiredMsgId) &&
+ (mostFrequentMsgIdToDefer == null ||
+ newAcquiredMsgCount > msgCounts.getOrDefault(mostFrequentMsgIdToDefer!!, 0))
+ ) {
+ mostFrequentMsgIdToDefer = acquiredMsgId
+ }
+ }
+
+ /**
+ * Get the most frequent deferred message that meets the [THRESHOLD] percentage of processed
+ * messages excluding [excludedMessages].
+ * @return null if no messages have been deferred OR deferred messages didn't meet the
+ * [THRESHOLD] percentage of messages to show.
+ */
+ fun getDeferredMessage(): CharSequence? {
+ mostFrequentMsgIdToDefer?.let {
+ if (msgCounts.getOrDefault(it, 0) > (THRESHOLD * totalRelevantMessages)) {
+ return msgIdToCharSequence[mostFrequentMsgIdToDefer]
+ }
+ }
+
+ return null
+ }
+ companion object {
+ const val THRESHOLD = .5f
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 47dc5c2a5513..2251ab5460d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,6 +19,10 @@ package com.android.systemui.statusbar;
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.BiometricFaceConstants.FACE_ACQUIRED_FIRST_FRAME_RECEIVED;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_GOOD;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
import static android.hardware.biometrics.BiometricSourceType.FACE;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -78,6 +82,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
+import com.android.systemui.biometrics.BiometricMessageDeferral;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -178,7 +183,7 @@ public class KeyguardIndicationController {
private boolean mBatteryPresent = true;
private long mChargingTimeRemaining;
private String mBiometricErrorMessageToShowOnScreenOn;
- private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
+ private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
private boolean mInited;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -249,11 +254,11 @@ public class KeyguardIndicationController {
mScreenLifecycle = screenLifecycle;
mScreenLifecycle.addObserver(mScreenObserver);
- mCoExFaceHelpMsgIdsToShow = new HashSet<>();
+ mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
int[] msgIds = context.getResources().getIntArray(
com.android.systemui.R.array.config_face_help_msgs_when_fingerprint_enrolled);
for (int msgId : msgIds) {
- mCoExFaceHelpMsgIdsToShow.add(msgId);
+ mCoExFaceAcquisitionMsgIdsToShow.add(msgId);
}
mHandler = new Handler(mainLooper) {
@@ -990,7 +995,7 @@ public class KeyguardIndicationController {
mTopIndicationView == null ? null : mTopIndicationView.getText()));
pw.println(" computePowerIndication(): " + computePowerIndication());
pw.println(" trustGrantedIndication: " + getTrustGrantedIndication());
- pw.println(" mCoExFaceHelpMsgIdsToShow=" + mCoExFaceHelpMsgIdsToShow);
+ pw.println(" mCoExFaceHelpMsgIdsToShow=" + mCoExFaceAcquisitionMsgIdsToShow);
mRotateTextViewController.dump(pw, args);
}
@@ -1048,6 +1053,17 @@ public class KeyguardIndicationController {
return;
}
+ if (biometricSourceType == FACE) {
+ if (msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED) {
+ mFaceAcquiredMessageDeferral.reset();
+ } else {
+ mFaceAcquiredMessageDeferral.processMessage(msgId, helpString);
+ if (mFaceAcquiredMessageDeferral.shouldDefer(msgId)) {
+ return;
+ }
+ }
+ }
+
final boolean faceAuthSoftError = biometricSourceType == FACE
&& msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
final boolean faceAuthFailed = biometricSourceType == FACE
@@ -1055,9 +1071,9 @@ public class KeyguardIndicationController {
final boolean isUnlockWithFingerprintPossible =
mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
getCurrentUser());
- if (faceAuthSoftError
- && isUnlockWithFingerprintPossible
- && !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
+ final boolean isCoExFaceAcquisitionMessage =
+ faceAuthSoftError && isUnlockWithFingerprintPossible;
+ if (isCoExFaceAcquisitionMessage && !mCoExFaceAcquisitionMsgIdsToShow.contains(msgId)) {
if (DEBUG) {
Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString
+ ", due to co-ex logic");
@@ -1067,7 +1083,12 @@ public class KeyguardIndicationController {
mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
mInitialTextColorState);
} else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
- if (faceAuthFailed && isUnlockWithFingerprintPossible) {
+ if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) {
+ showBiometricMessage(
+ helpString,
+ mContext.getString(R.string.keyguard_suggest_fingerprint)
+ );
+ } else if (faceAuthFailed && isUnlockWithFingerprintPossible) {
showBiometricMessage(
mContext.getString(R.string.keyguard_face_failed),
mContext.getString(R.string.keyguard_suggest_fingerprint)
@@ -1090,34 +1111,44 @@ public class KeyguardIndicationController {
@Override
public void onBiometricError(int msgId, String errString,
BiometricSourceType biometricSourceType) {
- if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
- return;
+ CharSequence deferredFaceMessage = null;
+ if (biometricSourceType == FACE) {
+ deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
+ mFaceAcquiredMessageDeferral.reset();
}
- if (biometricSourceType == FACE
- && msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
- // suppress all face UNABLE_TO_PROCESS errors
+ if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
if (DEBUG) {
- Log.d(TAG, "skip showing FACE_ERROR_UNABLE_TO_PROCESS errString="
- + errString);
+ Log.d(TAG, "suppressingBiometricError msgId=" + msgId
+ + " source=" + biometricSourceType);
}
- } else if (biometricSourceType == FACE
- && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+ } else if (biometricSourceType == FACE && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+ // Co-ex: show deferred message OR nothing
if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
- getCurrentUser())) {
- // no message if fingerprint is also enrolled
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ // if we're on the lock screen (bouncer isn't showing), show the deferred msg
+ if (deferredFaceMessage != null
+ && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ showBiometricMessage(
+ deferredFaceMessage,
+ mContext.getString(R.string.keyguard_suggest_fingerprint)
+ );
+ return;
+ }
+
+ // otherwise, don't show any message
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
+ // Face-only: The face timeout message is not very actionable, let's ask the user to
// manually retry.
- if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
- mStatusBarKeyguardViewManager.showBouncerMessage(
- mContext.getResources().getString(R.string.keyguard_try_fingerprint),
- mInitialTextColorState
+ if (deferredFaceMessage != null) {
+ showBiometricMessage(
+ deferredFaceMessage,
+ mContext.getString(R.string.keyguard_unlock)
);
} else {
// suggest swiping up to unlock (try face auth again or swipe up to bouncer)
@@ -1134,8 +1165,9 @@ public class KeyguardIndicationController {
private boolean shouldSuppressBiometricError(int msgId,
BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
- if (biometricSourceType == BiometricSourceType.FINGERPRINT)
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
return shouldSuppressFingerprintError(msgId, updateMonitor);
+ }
if (biometricSourceType == FACE) {
return shouldSuppressFaceError(msgId, updateMonitor);
}
@@ -1161,7 +1193,8 @@ public class KeyguardIndicationController {
// check of whether non-strong biometric is allowed
return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
&& msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
- || msgId == FaceManager.FACE_ERROR_CANCELED);
+ || msgId == FaceManager.FACE_ERROR_CANCELED
+ || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS);
}
@@ -1200,10 +1233,11 @@ public class KeyguardIndicationController {
boolean isStrongBiometric) {
super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
hideBiometricMessage();
-
- if (biometricSourceType == FACE
- && !mKeyguardBypassController.canBypass()) {
- showActionToUnlock();
+ if (biometricSourceType == FACE) {
+ mFaceAcquiredMessageDeferral.reset();
+ if (!mKeyguardBypassController.canBypass()) {
+ showActionToUnlock();
+ }
}
}
@@ -1274,4 +1308,14 @@ public class KeyguardIndicationController {
}
}
};
+
+ private final BiometricMessageDeferral mFaceAcquiredMessageDeferral =
+ new BiometricMessageDeferral(
+ Set.of(
+ FACE_ACQUIRED_GOOD,
+ FACE_ACQUIRED_START,
+ FACE_ACQUIRED_FIRST_FRAME_RECEIVED
+ ),
+ Set.of(FACE_ACQUIRED_TOO_DARK)
+ );
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
new file mode 100644
index 000000000000..419fedf99c15
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BiometricMessageDeferralTest : SysuiTestCase() {
+
+ @Test
+ fun testProcessNoMessages_noDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf())
+
+ assertNull(biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testProcessNonDeferredMessages_noDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+ // WHEN there are no deferred messages processed
+ for (i in 0..3) {
+ biometricMessageDeferral.processMessage(4, "test")
+ }
+
+ // THEN getDeferredMessage is null
+ assertNull(biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testAllProcessedMessagesWereDeferred() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1))
+
+ // WHEN all the processed messages are a deferred message
+ for (i in 0..3) {
+ biometricMessageDeferral.processMessage(1, "test")
+ }
+
+ // THEN deferredMessage will return the string associated with the deferred msgId
+ assertEquals("test", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testReturnsMostFrequentDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+ // WHEN there's two msgId=1 processed and one msgId=2 processed
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(2, "msgId-2")
+
+ // THEN the most frequent deferred message is that meets the threshold is returned
+ assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testDeferredMessage_mustMeetThreshold() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1))
+
+ // WHEN more nonDeferredMessages are shown than the deferred message
+ val totalMessages = 10
+ val nonDeferredMessagesCount =
+ (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+ for (i in 0 until nonDeferredMessagesCount) {
+ biometricMessageDeferral.processMessage(4, "non-deferred-msg")
+ }
+ for (i in nonDeferredMessagesCount until totalMessages) {
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ }
+
+ // THEN there's no deferred message because it didn't meet the threshold
+ assertNull(biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testDeferredMessage_manyExcludedMessages_getDeferredMessage() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(3), setOf(1))
+
+ // WHEN more excludedMessages are shown than the deferred message
+ val totalMessages = 10
+ val excludedMessagesCount = (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+ for (i in 0 until excludedMessagesCount) {
+ biometricMessageDeferral.processMessage(3, "excluded-msg")
+ }
+ for (i in excludedMessagesCount until totalMessages) {
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ }
+
+ // THEN there IS a deferred message because the deferred msg meets the threshold amongst the
+ // non-excluded messages
+ assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testResetClearsOutCounts() {
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+ // GIVEN two msgId=1 events processed
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+ biometricMessageDeferral.processMessage(1, "msgId-1")
+
+ // WHEN counts are reset and then a single deferred message is processed (msgId=2)
+ biometricMessageDeferral.reset()
+ biometricMessageDeferral.processMessage(2, "msgId-2")
+
+ // THEN msgId-2 is the deferred message since the two msgId=1 events were reset
+ assertEquals("msgId-2", biometricMessageDeferral.getDeferredMessage())
+ }
+
+ @Test
+ fun testShouldDefer() {
+ // GIVEN should defer msgIds 1 and 2
+ val biometricMessageDeferral = BiometricMessageDeferral(setOf(3), setOf(1, 2))
+
+ // THEN shouldDefer returns true for ids 1 & 2
+ assertTrue(biometricMessageDeferral.shouldDefer(1))
+ assertTrue(biometricMessageDeferral.shouldDefer(2))
+
+ // THEN should defer returns false for ids 3 & 4
+ assertFalse(biometricMessageDeferral.shouldDefer(3))
+ assertFalse(biometricMessageDeferral.shouldDefer(4))
+ }
+}
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 798f47d2d6cb..d73d07ca1423 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
@@ -65,7 +66,6 @@ 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;
import android.os.BatteryManager;
import android.os.Looper;
@@ -602,7 +602,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
String message = mContext.getString(R.string.keyguard_unlock);
mController.setVisible(true);
- mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+ mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
"A message", BiometricSourceType.FACE);
verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
@@ -636,7 +636,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
mController.setVisible(true);
- mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+ mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
"A message", BiometricSourceType.FACE);
verify(mStatusBarKeyguardViewManager).showBouncerMessage(eq(message), any());
@@ -651,7 +651,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mController.setVisible(true);
mController.getKeyguardCallback().onBiometricError(
- FaceManager.FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
+ FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
}
@@ -698,8 +698,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
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
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
};
for (int msgId : msgIds) {
mKeyguardUpdateMonitorCallback.onBiometricHelp(
@@ -728,8 +727,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
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
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
};
for (int msgId : msgIds) {
final String numberedHelpString = helpString + msgId;
@@ -743,6 +741,64 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
}
@Test
+ public void sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled() {
+ createController();
+
+ // GIVEN fingerprint NOT enrolled
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ 0)).thenReturn(false);
+
+ // WHEN help message received
+ final String helpString = "helpMsg";
+ mKeyguardUpdateMonitorCallback.onBiometricHelp(
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+ helpString,
+ BiometricSourceType.FACE
+ );
+
+ // THEN help message not shown yet
+ verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+ // WHEN face timeout error received
+ mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+ BiometricSourceType.FACE);
+
+ // THEN the low light message shows with suggestion to swipe up to unlock
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+ mContext.getString(R.string.keyguard_unlock));
+ }
+
+ @Test
+ public void sendTooDarkFaceHelpMessages_onTimeout_fingerprintEnrolled() {
+ createController();
+
+ // GIVEN fingerprint enrolled
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ 0)).thenReturn(true);
+
+ // WHEN help message received
+ final String helpString = "helpMsg";
+ mKeyguardUpdateMonitorCallback.onBiometricHelp(
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+ helpString,
+ BiometricSourceType.FACE
+ );
+
+ // THEN help message not shown yet
+ verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+ // WHEN face timeout error received
+ mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+ BiometricSourceType.FACE);
+
+ // THEN the low light message shows and suggests trying fingerprint
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+ verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+ mContext.getString(R.string.keyguard_suggest_fingerprint));
+ }
+
+ @Test
public void updateMonitor_listenerUpdatesIndication() {
createController();
String restingIndication = "Resting indication";