Show low light soft-error on FACE_TIMEOUT
If it meets a threshold of 70% of the acquired messages received by SysUI. Test: atest KeyguardIndicationControllerTest Test: atest BiometricMessageDeferralTest Test: enroll face auth, go into a low-light area, attempt face auth and see the "low light" message Fixes: 244362700 Change-Id: I270c2459a89d087f9a9ea5de52a8c5179d9991ce
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@ 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;
|
||||
@@ -79,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;
|
||||
@@ -1049,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
|
||||
@@ -1096,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)
|
||||
@@ -1140,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);
|
||||
}
|
||||
@@ -1167,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1206,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1280,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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -667,8 +667,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
final String helpString = "helpString";
|
||||
final int[] msgIds = new int[]{
|
||||
BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED,
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
|
||||
BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED
|
||||
};
|
||||
Set<CharSequence> messages = new HashSet<>();
|
||||
for (int msgId : msgIds) {
|
||||
@@ -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,7 +741,36 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendTooDarkFaceHelpMessages_fingerprintEnrolled() {
|
||||
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
|
||||
@@ -758,7 +785,14 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
BiometricSourceType.FACE
|
||||
);
|
||||
|
||||
// THEN help message shown and try fingerprint message shown
|
||||
// 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));
|
||||
|
||||
Reference in New Issue
Block a user