Do not ignore lockout error from face if it's class3.

Test: atest AuthBiometricFingerprintAndFaceViewTest
Bug: 277261318
Change-Id: Ibe971762f0dba4eabbd1b0f566e7df8e19b4422d
This commit is contained in:
Hao Dong
2023-04-06 21:54:01 +00:00
parent ef0421cfeb
commit 30cea5fce9
5 changed files with 72 additions and 8 deletions

View File

@@ -1970,8 +1970,8 @@
<string name="face_error_user_canceled">Face Unlock canceled by user</string>
<!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
<string name="face_error_lockout">Too many attempts. Try again later.</string>
<!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
<string name="face_error_lockout_permanent">Too many attempts. Face Unlock disabled.</string>
<!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=100] -->
<string name="face_error_lockout_permanent">Too many attempts. Face Unlock unavailable.</string>
<!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
<string name="face_error_lockout_screen_lock">Too many attempts. Enter screen lock instead.</string>
<!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->

View File

@@ -19,6 +19,8 @@ package com.android.systemui.biometrics
import android.content.Context
import android.hardware.biometrics.BiometricAuthenticator.Modality
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
import android.hardware.biometrics.BiometricConstants
import android.hardware.face.FaceManager
import android.util.AttributeSet
import com.android.systemui.R
@@ -27,6 +29,7 @@ class AuthBiometricFingerprintAndFaceView(
context: Context,
attrs: AttributeSet?
) : AuthBiometricFingerprintView(context, attrs) {
var isFaceClass3 = false
constructor (context: Context) : this(context, null)
@@ -34,10 +37,22 @@ class AuthBiometricFingerprintAndFaceView(
override fun forceRequireConfirmation(@Modality modality: Int) = modality == TYPE_FACE
override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int) = modality == TYPE_FACE
override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int, unsuccessfulReason: String) =
modality == TYPE_FACE && !(isFaceClass3 && isLockoutErrorString(unsuccessfulReason))
override fun onPointerDown(failedModalities: Set<Int>) = failedModalities.contains(TYPE_FACE)
override fun createIconController(): AuthIconController =
AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)
private fun isLockoutErrorString(unsuccessfulReason: String) =
unsuccessfulReason == FaceManager.getErrorString(
mContext,
BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
0 /*vendorCode */
) || unsuccessfulReason == FaceManager.getErrorString(
mContext,
BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
0 /*vendorCode */
)
}

View File

@@ -258,7 +258,8 @@ public abstract class AuthBiometricView extends LinearLayout {
}
/** Ignore all events from this (secondary) modality except successful authentication. */
protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality) {
protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality,
String unsuccessfulReason) {
return false;
}
@@ -541,7 +542,7 @@ public abstract class AuthBiometricView extends LinearLayout {
*/
public void onAuthenticationFailed(
@Modality int modality, @Nullable String failureReason) {
if (ignoreUnsuccessfulEventsFrom(modality)) {
if (ignoreUnsuccessfulEventsFrom(modality, failureReason)) {
return;
}
@@ -556,7 +557,7 @@ public abstract class AuthBiometricView extends LinearLayout {
* @param error message
*/
public void onError(@Modality int modality, String error) {
if (ignoreUnsuccessfulEventsFrom(modality)) {
if (ignoreUnsuccessfulEventsFrom(modality, error)) {
return;
}
@@ -586,7 +587,7 @@ public abstract class AuthBiometricView extends LinearLayout {
* @param help message
*/
public void onHelp(@Modality int modality, String help) {
if (ignoreUnsuccessfulEventsFrom(modality)) {
if (ignoreUnsuccessfulEventsFrom(modality, help)) {
return;
}
if (mSize != AuthDialog.SIZE_MEDIUM) {

View File

@@ -18,6 +18,7 @@ package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;
@@ -383,6 +384,8 @@ public class AuthContainerView extends LinearLayout
fingerprintAndFaceView.setSensorProperties(fpProperties);
fingerprintAndFaceView.setScaleFactorProvider(config.mScaleProvider);
fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
fingerprintAndFaceView.setFaceClass3(
faceProperties.sensorStrength == STRENGTH_STRONG);
mBiometricView = fingerprintAndFaceView;
} else if (fpProperties != null) {
final AuthBiometricFingerprintView fpView =

View File

@@ -18,6 +18,8 @@ package com.android.systemui.biometrics
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
import android.hardware.biometrics.BiometricConstants
import android.hardware.face.FaceManager
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.view.View
@@ -34,6 +36,7 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.times
import org.mockito.junit.MockitoJUnit
@@ -98,7 +101,7 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
}
@Test
fun ignoresFaceErrors() {
fun ignoresFaceErrors_faceIsNotClass3_notLockoutError() {
biometricView.onDialogAnimatedIn()
biometricView.onError(TYPE_FACE, "not a face")
waitForIdleSync()
@@ -113,5 +116,47 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
}
@Test
fun doNotIgnoresFaceErrors_faceIsClass3_notLockoutError() {
biometricView.isFaceClass3 = true
biometricView.onDialogAnimatedIn()
biometricView.onError(TYPE_FACE, "not a face")
waitForIdleSync()
assertThat(biometricView.isAuthenticating).isTrue()
verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)
biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
TestableLooper.get(this).moveTimeForward(1000)
waitForIdleSync()
verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
}
@Test
fun doNotIgnoresFaceErrors_faceIsClass3_lockoutError() {
biometricView.isFaceClass3 = true
biometricView.onDialogAnimatedIn()
biometricView.onError(
TYPE_FACE,
FaceManager.getErrorString(
biometricView.context,
BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
0 /*vendorCode */
)
)
waitForIdleSync()
assertThat(biometricView.isAuthenticating).isTrue()
verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
TestableLooper.get(this).moveTimeForward(1000)
waitForIdleSync()
verify(callback, times(2)).onAction(AuthBiometricView.Callback.ACTION_ERROR)
}
override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
}