Merge "Use more face-acquired frames for msg deferral" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
99b6f2bd5b
@@ -611,6 +611,33 @@
|
||||
2 - Override the setting to never bypass keyguard -->
|
||||
<integer name="config_face_unlock_bypass_override">0</integer>
|
||||
|
||||
<!-- Messages that should NOT be shown to the user during face authentication on keyguard.
|
||||
This includes both lockscreen and bouncer. This should be used to hide messages that may be
|
||||
too chatty or messages that the user can't do much about. Entries are defined in
|
||||
android.hardware.biometrics.face@1.0 types.hal.
|
||||
|
||||
Although not visibly shown to the user, these acquired messages (sent per face auth frame)
|
||||
are still counted towards the total frames to determine whether a deferred message
|
||||
(see config_face_help_msgs_defer_until_timeout) meets the threshold % of frames to show on
|
||||
face timeout. -->
|
||||
<integer-array name="config_face_acquire_device_entry_ignorelist" translatable="false" >
|
||||
</integer-array>
|
||||
|
||||
<!-- Which face help messages to defer until face auth times out. If face auth is cancelled
|
||||
or ends on another error, then the message is never surfaced. May also never surface
|
||||
if it doesn't meet a threshold % of authentication frames specified by.
|
||||
config_face_help_msgs_defer_until_timeout_threshold. -->
|
||||
<integer-array name="config_face_help_msgs_defer_until_timeout">
|
||||
</integer-array>
|
||||
|
||||
<!-- Percentage of face auth frames received required to show a deferred message at
|
||||
FACE_ERROR_TIMEOUT. See config_face_help_msgs_defer_until_timeout for messages
|
||||
that are deferred.-->
|
||||
<item name="config_face_help_msgs_defer_until_timeout_threshold"
|
||||
translatable="false" format="float" type="dimen">
|
||||
.75
|
||||
</item>
|
||||
|
||||
<!-- 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">
|
||||
|
||||
@@ -157,6 +157,7 @@ import com.google.android.collect.Lists;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -167,6 +168,7 @@ import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
@@ -281,6 +283,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
private final AuthController mAuthController;
|
||||
private final StatusBarStateController mStatusBarStateController;
|
||||
private final UiEventLogger mUiEventLogger;
|
||||
private final Set<Integer> mFaceAcquiredInfoIgnoreList;
|
||||
private int mStatusBarState;
|
||||
private final StatusBarStateController.StateListener mStatusBarStateControllerListener =
|
||||
new StatusBarStateController.StateListener() {
|
||||
@@ -1023,6 +1026,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
|
||||
private void handleFaceAuthFailed() {
|
||||
Assert.isMainThread();
|
||||
mLogger.d("onFaceAuthFailed");
|
||||
mFaceCancelSignal = null;
|
||||
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
@@ -1639,6 +1643,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
|
||||
if (mFaceAcquiredInfoIgnoreList.contains(helpMsgId)) {
|
||||
return;
|
||||
}
|
||||
handleFaceHelp(helpMsgId, helpString.toString());
|
||||
}
|
||||
|
||||
@@ -1931,6 +1938,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
|
||||
mWakeOnFingerprintAcquiredStart = context.getResources()
|
||||
.getBoolean(com.android.internal.R.bool.kg_wake_on_acquire_start);
|
||||
mFaceAcquiredInfoIgnoreList = Arrays.stream(
|
||||
mContext.getResources().getIntArray(
|
||||
R.array.config_face_acquire_device_entry_ignorelist))
|
||||
.boxed()
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
mHandler = new Handler(mainLooper) {
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.keyguard.logging
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.log.LogBuffer
|
||||
import com.android.systemui.log.LogLevel.DEBUG
|
||||
import com.android.systemui.log.dagger.BiometricMessagesLog
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Helper class for logging for [com.android.systemui.biometrics.FaceHelpMessageDeferral] */
|
||||
@SysUISingleton
|
||||
class FaceMessageDeferralLogger
|
||||
@Inject
|
||||
constructor(@BiometricMessagesLog private val logBuffer: LogBuffer) :
|
||||
BiometricMessageDeferralLogger(logBuffer, "FaceMessageDeferralLogger")
|
||||
|
||||
open class BiometricMessageDeferralLogger(
|
||||
private val logBuffer: LogBuffer,
|
||||
private val tag: String
|
||||
) {
|
||||
fun reset() {
|
||||
logBuffer.log(tag, DEBUG, "reset")
|
||||
}
|
||||
|
||||
fun logUpdateMessage(acquiredInfo: Int, helpString: String) {
|
||||
logBuffer.log(
|
||||
tag,
|
||||
DEBUG,
|
||||
{
|
||||
int1 = acquiredInfo
|
||||
str1 = helpString
|
||||
},
|
||||
{ "updateMessage acquiredInfo=$int1 helpString=$str1" }
|
||||
)
|
||||
}
|
||||
|
||||
fun logFrameProcessed(
|
||||
acquiredInfo: Int,
|
||||
totalFrames: Int,
|
||||
mostFrequentAcquiredInfoToDefer: String? // may not meet the threshold
|
||||
) {
|
||||
logBuffer.log(
|
||||
tag,
|
||||
DEBUG,
|
||||
{
|
||||
int1 = acquiredInfo
|
||||
int2 = totalFrames
|
||||
str1 = mostFrequentAcquiredInfoToDefer
|
||||
},
|
||||
{
|
||||
"frameProcessed acquiredInfo=$int1 totalFrames=$int2 " +
|
||||
"messageToShowOnTimeout=$str1"
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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.content.res.Resources
|
||||
import com.android.keyguard.logging.BiometricMessageDeferralLogger
|
||||
import com.android.keyguard.logging.FaceMessageDeferralLogger
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Provides whether a face acquired help message should be shown immediately when its received or
|
||||
* should be shown when face auth times out. See [updateMessage] and [getDeferredMessage].
|
||||
*/
|
||||
@SysUISingleton
|
||||
class FaceHelpMessageDeferral
|
||||
@Inject
|
||||
constructor(
|
||||
@Main resources: Resources,
|
||||
logBuffer: FaceMessageDeferralLogger,
|
||||
dumpManager: DumpManager
|
||||
) :
|
||||
BiometricMessageDeferral(
|
||||
resources.getIntArray(R.array.config_face_help_msgs_defer_until_timeout).toHashSet(),
|
||||
resources.getFloat(R.dimen.config_face_help_msgs_defer_until_timeout_threshold),
|
||||
logBuffer,
|
||||
dumpManager
|
||||
)
|
||||
|
||||
/**
|
||||
* @property messagesToDefer messages that shouldn't show immediately when received, but may be
|
||||
* shown later if the message is the most frequent acquiredInfo processed and meets [threshold]
|
||||
* percentage of all passed acquired frames.
|
||||
*/
|
||||
open class BiometricMessageDeferral(
|
||||
private val messagesToDefer: Set<Int>,
|
||||
private val threshold: Float,
|
||||
private val logBuffer: BiometricMessageDeferralLogger,
|
||||
dumpManager: DumpManager
|
||||
) : Dumpable {
|
||||
private val acquiredInfoToFrequency: MutableMap<Int, Int> = HashMap()
|
||||
private val acquiredInfoToHelpString: MutableMap<Int, String> = HashMap()
|
||||
private var mostFrequentAcquiredInfoToDefer: Int? = null
|
||||
private var totalFrames = 0
|
||||
|
||||
init {
|
||||
dumpManager.registerDumpable(this.javaClass.name, this)
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.println("messagesToDefer=$messagesToDefer")
|
||||
pw.println("totalFrames=$totalFrames")
|
||||
pw.println("threshold=$threshold")
|
||||
}
|
||||
|
||||
/** Reset all saved counts. */
|
||||
fun reset() {
|
||||
totalFrames = 0
|
||||
mostFrequentAcquiredInfoToDefer = null
|
||||
acquiredInfoToFrequency.clear()
|
||||
acquiredInfoToHelpString.clear()
|
||||
logBuffer.reset()
|
||||
}
|
||||
|
||||
/** Updates the message associated with the acquiredInfo if it's a message we may defer. */
|
||||
fun updateMessage(acquiredInfo: Int, helpString: String) {
|
||||
if (!messagesToDefer.contains(acquiredInfo)) {
|
||||
return
|
||||
}
|
||||
if (!Objects.equals(acquiredInfoToHelpString[acquiredInfo], helpString)) {
|
||||
logBuffer.logUpdateMessage(acquiredInfo, helpString)
|
||||
acquiredInfoToHelpString[acquiredInfo] = helpString
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether the given message should be deferred instead of being shown immediately. */
|
||||
fun shouldDefer(acquiredMsgId: Int): Boolean {
|
||||
return messagesToDefer.contains(acquiredMsgId)
|
||||
}
|
||||
|
||||
/** Adds the acquiredInfo frame to the counts. We account for all frames. */
|
||||
fun processFrame(acquiredInfo: Int) {
|
||||
if (messagesToDefer.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
totalFrames++
|
||||
|
||||
val newAcquiredInfoCount = acquiredInfoToFrequency.getOrDefault(acquiredInfo, 0) + 1
|
||||
acquiredInfoToFrequency[acquiredInfo] = newAcquiredInfoCount
|
||||
if (
|
||||
messagesToDefer.contains(acquiredInfo) &&
|
||||
(mostFrequentAcquiredInfoToDefer == null ||
|
||||
newAcquiredInfoCount >
|
||||
acquiredInfoToFrequency.getOrDefault(mostFrequentAcquiredInfoToDefer!!, 0))
|
||||
) {
|
||||
mostFrequentAcquiredInfoToDefer = acquiredInfo
|
||||
}
|
||||
|
||||
logBuffer.logFrameProcessed(
|
||||
acquiredInfo,
|
||||
totalFrames,
|
||||
mostFrequentAcquiredInfoToDefer?.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most frequent deferred message that meets the [threshold] percentage of processed
|
||||
* frames.
|
||||
* @return null if no acquiredInfo have been deferred OR deferred messages didn't meet the
|
||||
* [threshold] percentage.
|
||||
*/
|
||||
fun getDeferredMessage(): CharSequence? {
|
||||
mostFrequentAcquiredInfoToDefer?.let {
|
||||
if (acquiredInfoToFrequency.getOrDefault(it, 0) > (threshold * totalFrames)) {
|
||||
return acquiredInfoToHelpString[it]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.log.dagger;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
/**
|
||||
* A {@link com.android.systemui.log.LogBuffer} for BiometricMessages processing such as
|
||||
* {@link com.android.systemui.biometrics.FaceHelpMessageDeferral}
|
||||
*/
|
||||
@Qualifier
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface BiometricMessagesLog {
|
||||
}
|
||||
@@ -286,6 +286,17 @@ public class LogModule {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a {@link LogBuffer} for use by
|
||||
* {@link com.android.systemui.biometrics.FaceHelpMessageDeferral}.
|
||||
*/
|
||||
@Provides
|
||||
@SysUISingleton
|
||||
@BiometricMessagesLog
|
||||
public static LogBuffer provideBiometricMessagesLogBuffer(LogBufferFactory factory) {
|
||||
return factory.create("BiometricMessagesLog", 150);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a {@link LogBuffer} for use by the status bar network controller.
|
||||
*/
|
||||
|
||||
@@ -19,9 +19,6 @@ 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;
|
||||
@@ -53,6 +50,7 @@ import android.content.pm.UserInfo;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.hardware.biometrics.BiometricFaceConstants;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
@@ -82,7 +80,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.biometrics.FaceHelpMessageDeferral;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
@@ -184,6 +182,7 @@ public class KeyguardIndicationController {
|
||||
private long mChargingTimeRemaining;
|
||||
private String mBiometricErrorMessageToShowOnScreenOn;
|
||||
private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
|
||||
private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral;
|
||||
private boolean mInited;
|
||||
|
||||
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
|
||||
@@ -233,7 +232,8 @@ public class KeyguardIndicationController {
|
||||
LockPatternUtils lockPatternUtils,
|
||||
ScreenLifecycle screenLifecycle,
|
||||
KeyguardBypassController keyguardBypassController,
|
||||
AccessibilityManager accessibilityManager) {
|
||||
AccessibilityManager accessibilityManager,
|
||||
FaceHelpMessageDeferral faceHelpMessageDeferral) {
|
||||
mContext = context;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mDevicePolicyManager = devicePolicyManager;
|
||||
@@ -254,6 +254,7 @@ public class KeyguardIndicationController {
|
||||
mScreenLifecycle = screenLifecycle;
|
||||
mScreenLifecycle.addObserver(mScreenObserver);
|
||||
|
||||
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
|
||||
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
|
||||
int[] msgIds = context.getResources().getIntArray(
|
||||
com.android.systemui.R.array.config_face_help_msgs_when_fingerprint_enrolled);
|
||||
@@ -1040,9 +1041,23 @@ public class KeyguardIndicationController {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricAcquired(BiometricSourceType biometricSourceType, int acquireInfo) {
|
||||
if (biometricSourceType == FACE) {
|
||||
mFaceAcquiredMessageDeferral.processFrame(acquireInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricHelp(int msgId, String helpString,
|
||||
BiometricSourceType biometricSourceType) {
|
||||
if (biometricSourceType == FACE) {
|
||||
mFaceAcquiredMessageDeferral.updateMessage(msgId, helpString);
|
||||
if (mFaceAcquiredMessageDeferral.shouldDefer(msgId)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/141025588): refactor to reduce repetition of code/comments
|
||||
// Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
|
||||
// as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
|
||||
@@ -1053,17 +1068,6 @@ 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
|
||||
@@ -1108,12 +1112,24 @@ public class KeyguardIndicationController {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
|
||||
if (biometricSourceType == FACE) {
|
||||
mFaceAcquiredMessageDeferral.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricError(int msgId, String errString,
|
||||
BiometricSourceType biometricSourceType) {
|
||||
CharSequence deferredFaceMessage = null;
|
||||
if (biometricSourceType == FACE) {
|
||||
deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
|
||||
if (msgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT) {
|
||||
deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "showDeferredFaceMessage msgId=" + deferredFaceMessage);
|
||||
}
|
||||
}
|
||||
mFaceAcquiredMessageDeferral.reset();
|
||||
}
|
||||
|
||||
@@ -1308,14 +1324,4 @@ 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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.keyguard.logging.BiometricMessageDeferralLogger
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class FaceHelpMessageDeferralTest : SysuiTestCase() {
|
||||
val threshold = .75f
|
||||
@Mock lateinit var logger: BiometricMessageDeferralLogger
|
||||
@Mock lateinit var dumpManager: DumpManager
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProcessFrame_logs() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1))
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
verify(logger).logFrameProcessed(1, 1, "1")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateMessage_logs() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1))
|
||||
biometricMessageDeferral.updateMessage(1, "hi")
|
||||
verify(logger).logUpdateMessage(1, "hi")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReset_logs() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1))
|
||||
biometricMessageDeferral.reset()
|
||||
verify(logger).reset()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProcessNoMessages_noDeferredMessage() {
|
||||
val biometricMessageDeferral = createMsgDeferral(emptySet())
|
||||
|
||||
assertNull(biometricMessageDeferral.getDeferredMessage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProcessNonDeferredMessages_noDeferredMessage() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
|
||||
|
||||
// WHEN there are no deferred messages processed
|
||||
for (i in 0..3) {
|
||||
biometricMessageDeferral.processFrame(4)
|
||||
biometricMessageDeferral.updateMessage(4, "test")
|
||||
}
|
||||
|
||||
// THEN getDeferredMessage is null
|
||||
assertNull(biometricMessageDeferral.getDeferredMessage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProcessMessagesWithDeferredMessage_deferredMessageWasNeverGivenAString() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
|
||||
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
|
||||
assertNull(biometricMessageDeferral.getDeferredMessage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAllProcessedMessagesWereDeferred() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1))
|
||||
|
||||
// WHEN all the processed messages are a deferred message
|
||||
for (i in 0..3) {
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
biometricMessageDeferral.updateMessage(1, "test")
|
||||
}
|
||||
|
||||
// THEN deferredMessage will return the string associated with the deferred msgId
|
||||
assertEquals("test", biometricMessageDeferral.getDeferredMessage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReturnsMostFrequentDeferredMessage() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
|
||||
|
||||
// WHEN there's 80%of the messages are msgId=1 and 20% is msgId=2
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
biometricMessageDeferral.updateMessage(1, "msgId-1")
|
||||
|
||||
biometricMessageDeferral.processFrame(2)
|
||||
biometricMessageDeferral.updateMessage(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 = createMsgDeferral(setOf(1))
|
||||
|
||||
// WHEN more nonDeferredMessages are shown than the deferred message
|
||||
val totalMessages = 10
|
||||
val nonDeferredMessagesCount = (totalMessages * threshold).toInt() + 1
|
||||
for (i in 0 until nonDeferredMessagesCount) {
|
||||
biometricMessageDeferral.processFrame(4)
|
||||
biometricMessageDeferral.updateMessage(4, "non-deferred-msg")
|
||||
}
|
||||
for (i in nonDeferredMessagesCount until totalMessages) {
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
biometricMessageDeferral.updateMessage(1, "msgId-1")
|
||||
}
|
||||
|
||||
// THEN there's no deferred message because it didn't meet the threshold
|
||||
assertNull(biometricMessageDeferral.getDeferredMessage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResetClearsOutCounts() {
|
||||
val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
|
||||
|
||||
// GIVEN two msgId=1 events processed
|
||||
biometricMessageDeferral.processFrame(
|
||||
1,
|
||||
)
|
||||
biometricMessageDeferral.updateMessage(1, "msgId-1")
|
||||
biometricMessageDeferral.processFrame(1)
|
||||
biometricMessageDeferral.updateMessage(1, "msgId-1")
|
||||
|
||||
// WHEN counts are reset and then a single deferred message is processed (msgId=2)
|
||||
biometricMessageDeferral.reset()
|
||||
biometricMessageDeferral.processFrame(2)
|
||||
biometricMessageDeferral.updateMessage(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 = createMsgDeferral(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))
|
||||
}
|
||||
|
||||
private fun createMsgDeferral(messagesToDefer: Set<Int>): BiometricMessageDeferral {
|
||||
return BiometricMessageDeferral(messagesToDefer, threshold, logger, dumpManager)
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,10 @@ 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_ACQUIRED_TOO_DARK;
|
||||
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT;
|
||||
|
||||
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
|
||||
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
|
||||
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
|
||||
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
|
||||
@@ -86,6 +88,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
||||
import com.android.settingslib.fuelgauge.BatteryStatus;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dock.DockManager;
|
||||
import com.android.systemui.keyguard.KeyguardIndication;
|
||||
@@ -167,6 +170,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
@Mock
|
||||
private FaceHelpMessageDeferral mFaceHelpMessageDeferral;
|
||||
@Mock
|
||||
private ScreenLifecycle mScreenLifecycle;
|
||||
@Captor
|
||||
private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
|
||||
@@ -259,7 +264,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
|
||||
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
|
||||
mUserManager, mExecutor, mExecutor, mFalsingManager, mLockPatternUtils,
|
||||
mScreenLifecycle, mKeyguardBypassController, mAccessibilityManager);
|
||||
mScreenLifecycle, mKeyguardBypassController, mAccessibilityManager,
|
||||
mFaceHelpMessageDeferral);
|
||||
mController.init();
|
||||
mController.setIndicationArea(mIndicationArea);
|
||||
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
|
||||
@@ -535,7 +541,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
|
||||
mController.setVisible(true);
|
||||
mController.getKeyguardCallback().onBiometricHelp(
|
||||
KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
|
||||
BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
|
||||
BiometricSourceType.FACE);
|
||||
verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
|
||||
reset(mRotateTextViewController);
|
||||
@@ -582,7 +588,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
|
||||
// WHEN there's a face not recognized message
|
||||
mController.getKeyguardCallback().onBiometricHelp(
|
||||
KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
|
||||
BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
|
||||
message,
|
||||
BiometricSourceType.FACE);
|
||||
|
||||
@@ -748,8 +754,10 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
|
||||
0)).thenReturn(false);
|
||||
|
||||
// WHEN help message received
|
||||
// WHEN help message received and deferred message is valid
|
||||
final String helpString = "helpMsg";
|
||||
when(mFaceHelpMessageDeferral.getDeferredMessage()).thenReturn(helpString);
|
||||
when(mFaceHelpMessageDeferral.shouldDefer(FACE_ACQUIRED_TOO_DARK)).thenReturn(true);
|
||||
mKeyguardUpdateMonitorCallback.onBiometricHelp(
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
|
||||
helpString,
|
||||
@@ -777,8 +785,10 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
|
||||
0)).thenReturn(true);
|
||||
|
||||
// WHEN help message received
|
||||
// WHEN help message received and deferredMessage is valid
|
||||
final String helpString = "helpMsg";
|
||||
when(mFaceHelpMessageDeferral.getDeferredMessage()).thenReturn(helpString);
|
||||
when(mFaceHelpMessageDeferral.shouldDefer(FACE_ACQUIRED_TOO_DARK)).thenReturn(true);
|
||||
mKeyguardUpdateMonitorCallback.onBiometricHelp(
|
||||
BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
|
||||
helpString,
|
||||
@@ -1123,7 +1133,6 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, pressToOpen);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void coEx_faceSuccess_touchExplorationEnabled_showsFaceUnlockedSwipeToOpen() {
|
||||
// GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y enabled
|
||||
@@ -1269,6 +1278,87 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void faceOnAcquired_processFrame() {
|
||||
createController();
|
||||
|
||||
// WHEN face sends an acquired message
|
||||
final int acquireInfo = 1;
|
||||
mKeyguardUpdateMonitorCallback.onBiometricAcquired(BiometricSourceType.FACE, acquireInfo);
|
||||
|
||||
// THEN face help message deferral should process the acquired frame
|
||||
verify(mFaceHelpMessageDeferral).processFrame(acquireInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fingerprintOnAcquired_noProcessFrame() {
|
||||
createController();
|
||||
|
||||
// WHEN fingerprint sends an acquired message
|
||||
mKeyguardUpdateMonitorCallback.onBiometricAcquired(BiometricSourceType.FINGERPRINT, 1);
|
||||
|
||||
// THEN face help message deferral should NOT process any acquired frames
|
||||
verify(mFaceHelpMessageDeferral, never()).processFrame(anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBiometricHelp_fingerprint_faceHelpMessageDeferralDoesNothing() {
|
||||
createController();
|
||||
|
||||
// WHEN fingerprint sends an onBiometricHelp
|
||||
mKeyguardUpdateMonitorCallback.onBiometricHelp(
|
||||
1,
|
||||
"placeholder",
|
||||
BiometricSourceType.FINGERPRINT);
|
||||
|
||||
// THEN face help message deferral is NOT: reset, updated, or checked for shouldDefer
|
||||
verify(mFaceHelpMessageDeferral, never()).reset();
|
||||
verify(mFaceHelpMessageDeferral, never()).updateMessage(anyInt(), anyString());
|
||||
verify(mFaceHelpMessageDeferral, never()).shouldDefer(anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBiometricFailed_resetFaceHelpMessageDeferral() {
|
||||
createController();
|
||||
|
||||
// WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
|
||||
mKeyguardUpdateMonitorCallback.onBiometricAuthFailed(BiometricSourceType.FACE);
|
||||
|
||||
// THEN face help message deferral is reset
|
||||
verify(mFaceHelpMessageDeferral).reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBiometricError_resetFaceHelpMessageDeferral() {
|
||||
createController();
|
||||
|
||||
// WHEN face has an error
|
||||
mKeyguardUpdateMonitorCallback.onBiometricError(4, "string",
|
||||
BiometricSourceType.FACE);
|
||||
|
||||
// THEN face help message deferral is reset
|
||||
verify(mFaceHelpMessageDeferral).reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBiometricHelp_faceAcquiredInfo_faceHelpMessageDeferral() {
|
||||
createController();
|
||||
|
||||
// WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
|
||||
final int msgId = 1;
|
||||
final String helpString = "test";
|
||||
mKeyguardUpdateMonitorCallback.onBiometricHelp(
|
||||
msgId,
|
||||
"test",
|
||||
BiometricSourceType.FACE);
|
||||
|
||||
// THEN face help message deferral is NOT reset and message IS updated
|
||||
verify(mFaceHelpMessageDeferral, never()).reset();
|
||||
verify(mFaceHelpMessageDeferral).updateMessage(msgId, helpString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void sendUpdateDisclosureBroadcast() {
|
||||
mBroadcastReceiver.onReceive(mContext, new Intent());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user