summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/util/IndicationHelper.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt173
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java37
4 files changed, 265 insertions, 51 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/util/IndicationHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/util/IndicationHelper.kt
new file mode 100644
index 000000000000..712900161d48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/util/IndicationHelper.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 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.keyguard.util
+
+import android.hardware.biometrics.BiometricFaceConstants
+import android.hardware.biometrics.BiometricFingerprintConstants
+import android.hardware.biometrics.BiometricSourceType
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+@SysUISingleton
+class IndicationHelper
+@Inject
+constructor(
+ val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+) {
+ fun shouldSuppressErrorMsg(biometricSource: BiometricSourceType, msgId: Int): Boolean {
+ return when (biometricSource) {
+ BiometricSourceType.FINGERPRINT ->
+ (isPrimaryAuthRequired() && !isFingerprintLockoutErrorMsg(msgId)) ||
+ msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_CANCELED ||
+ msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED ||
+ msgId == BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED
+ BiometricSourceType.FACE ->
+ (isPrimaryAuthRequired() && !isFaceLockoutErrorMsg(msgId)) ||
+ msgId == BiometricFaceConstants.FACE_ERROR_CANCELED ||
+ msgId == BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS
+ else -> false
+ }
+ }
+
+ private fun isFingerprintLockoutErrorMsg(msgId: Int): Boolean {
+ return msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT ||
+ msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT
+ }
+
+ fun isFaceLockoutErrorMsg(msgId: Int): Boolean {
+ return msgId == BiometricFaceConstants.FACE_ERROR_LOCKOUT ||
+ msgId == BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT
+ }
+
+ private fun isPrimaryAuthRequired(): Boolean {
+ // 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 required), so it's ok to
+ // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+ // check of whether non-strong biometric is allowed since strong biometrics can still be
+ // used.
+ return !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 795bcadc8272..96924821cc1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -56,7 +56,6 @@ import android.content.res.Resources;
import android.graphics.Color;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.face.FaceManager;
-import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Looper;
@@ -86,6 +85,8 @@ import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -95,8 +96,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.keyguard.util.IndicationHelper;
import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -227,7 +227,8 @@ public class KeyguardIndicationController {
// triggered while the device is asleep
private final AlarmTimeout mHideTransientMessageHandler;
private final AlarmTimeout mHideBiometricMessageHandler;
- private FeatureFlags mFeatureFlags;
+ private final FeatureFlags mFeatureFlags;
+ private final IndicationHelper mIndicationHelper;
/**
* Creates a new KeyguardIndicationController and registers callbacks.
@@ -259,7 +260,8 @@ public class KeyguardIndicationController {
AlarmManager alarmManager,
UserTracker userTracker,
BouncerMessageInteractor bouncerMessageInteractor,
- FeatureFlags flags
+ FeatureFlags flags,
+ IndicationHelper indicationHelper
) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -286,6 +288,7 @@ public class KeyguardIndicationController {
mUserTracker = userTracker;
mBouncerMessageInteractor = bouncerMessageInteractor;
mFeatureFlags = flags;
+ mIndicationHelper = indicationHelper;
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
@@ -1249,13 +1252,13 @@ public class KeyguardIndicationController {
private void onFaceAuthError(int msgId, String errString) {
CharSequence deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
mFaceAcquiredMessageDeferral.reset();
- if (shouldSuppressFaceError(msgId)) {
- mKeyguardLogger.logBiometricMessage("suppressingFaceError", msgId, errString);
+ if (mIndicationHelper.shouldSuppressErrorMsg(FACE, msgId)) {
+ mKeyguardLogger.logBiometricMessage("KIC suppressingFaceError", msgId, errString);
return;
}
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
handleFaceAuthTimeoutError(deferredFaceMessage);
- } else if (isLockoutError(msgId)) {
+ } else if (mIndicationHelper.isFaceLockoutErrorMsg(msgId)) {
handleFaceLockoutError(errString);
} else {
showErrorMessageNowOrLater(errString, null);
@@ -1263,8 +1266,8 @@ public class KeyguardIndicationController {
}
private void onFingerprintAuthError(int msgId, String errString) {
- if (shouldSuppressFingerprintError(msgId)) {
- mKeyguardLogger.logBiometricMessage("suppressingFingerprintError",
+ if (mIndicationHelper.shouldSuppressErrorMsg(FINGERPRINT, msgId)) {
+ mKeyguardLogger.logBiometricMessage("KIC suppressingFingerprintError",
msgId,
errString);
} else {
@@ -1272,19 +1275,6 @@ public class KeyguardIndicationController {
}
}
- private boolean shouldSuppressFingerprintError(int msgId) {
- return ((isPrimaryAuthRequired() && !isLockoutError(msgId))
- || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
- || msgId == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED
- || msgId == FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED);
- }
-
- private boolean shouldSuppressFaceError(int msgId) {
- return ((isPrimaryAuthRequired() && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
- || msgId == FaceManager.FACE_ERROR_CANCELED
- || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS);
- }
-
@Override
public void onTrustChanged(int userId) {
if (!isCurrentUser(userId)) return;
@@ -1408,11 +1398,6 @@ public class KeyguardIndicationController {
return mContext.getString(followupMsgId);
}
- private static boolean isLockoutError(int msgId) {
- return msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT
- || msgId == FaceManager.FACE_ERROR_LOCKOUT;
- }
-
private void handleFaceAuthTimeoutError(@Nullable CharSequence deferredFaceMessage) {
mKeyguardLogger.logBiometricMessage("deferred message after face auth timeout",
null, String.valueOf(deferredFaceMessage));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
new file mode 100644
index 000000000000..fd0ff9b38eec
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 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.keyguard.util
+
+import android.hardware.biometrics.BiometricFaceConstants.BIOMETRIC_ERROR_POWER_PRESSED
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_CANCELED
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_VENDOR
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_CANCELED
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_TIMEOUT
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED
+import android.hardware.biometrics.BiometricSourceType
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.whenever
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class IndicationHelperTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ private lateinit var underTest: IndicationHelper
+
+ @Before
+ fun setup() {
+ underTest =
+ IndicationHelper(
+ keyguardUpdateMonitor,
+ )
+ }
+
+ @Test
+ fun suppressErrorMsg_faceErrorCancelled() {
+ givenPrimaryAuthNotRequired()
+ assertTrue(underTest.shouldSuppressErrorMsg(BiometricSourceType.FACE, FACE_ERROR_CANCELED))
+ }
+
+ @Test
+ fun suppressErrorMsg_faceErrorUnableToProcess() {
+ givenPrimaryAuthNotRequired()
+ assertTrue(
+ underTest.shouldSuppressErrorMsg(BiometricSourceType.FACE, FACE_ERROR_UNABLE_TO_PROCESS)
+ )
+ }
+
+ @Test
+ fun suppressErrorMsg_facePrimaryAuthRequired() {
+ givenPrimaryAuthRequired()
+ assertTrue(underTest.shouldSuppressErrorMsg(BiometricSourceType.FACE, FACE_ERROR_TIMEOUT))
+ }
+
+ @Test
+ fun doNotSuppressErrorMsg_facePrimaryAuthRequired_faceLockout() {
+ givenPrimaryAuthRequired()
+ assertFalse(underTest.shouldSuppressErrorMsg(BiometricSourceType.FACE, FACE_ERROR_LOCKOUT))
+ assertFalse(
+ underTest.shouldSuppressErrorMsg(BiometricSourceType.FACE, FACE_ERROR_LOCKOUT_PERMANENT)
+ )
+ }
+
+ @Test
+ fun suppressErrorMsg_fingerprintErrorCancelled() {
+ givenPrimaryAuthNotRequired()
+ assertTrue(
+ underTest.shouldSuppressErrorMsg(
+ BiometricSourceType.FINGERPRINT,
+ FINGERPRINT_ERROR_CANCELED
+ )
+ )
+ }
+
+ @Test
+ fun suppressErrorMsg_fingerprintErrorUserCancelled() {
+ givenPrimaryAuthNotRequired()
+ assertTrue(
+ underTest.shouldSuppressErrorMsg(
+ BiometricSourceType.FINGERPRINT,
+ FINGERPRINT_ERROR_USER_CANCELED
+ )
+ )
+ }
+
+ @Test
+ fun suppressErrorMsg_fingerprintErrorPowerPressed() {
+ givenPrimaryAuthNotRequired()
+ assertTrue(
+ underTest.shouldSuppressErrorMsg(
+ BiometricSourceType.FINGERPRINT,
+ BIOMETRIC_ERROR_POWER_PRESSED
+ )
+ )
+ }
+
+ @Test
+ fun suppressErrorMsg_fingerprintPrimaryAuthRequired() {
+ givenPrimaryAuthRequired()
+ assertTrue(
+ underTest.shouldSuppressErrorMsg(BiometricSourceType.FACE, FINGERPRINT_ERROR_TIMEOUT)
+ )
+ }
+
+ @Test
+ fun doNotSuppressErrorMsg_fingerprintPrimaryAuthRequired_fingerprintLockout() {
+ givenPrimaryAuthRequired()
+ assertFalse(
+ underTest.shouldSuppressErrorMsg(
+ BiometricSourceType.FINGERPRINT,
+ FINGERPRINT_ERROR_LOCKOUT
+ )
+ )
+ assertFalse(
+ underTest.shouldSuppressErrorMsg(
+ BiometricSourceType.FACE,
+ FINGERPRINT_ERROR_LOCKOUT_PERMANENT
+ )
+ )
+ }
+
+ @Test
+ fun isFaceLockoutErrorMsgId() {
+ givenPrimaryAuthRequired()
+ assertTrue(underTest.isFaceLockoutErrorMsg(FACE_ERROR_LOCKOUT))
+ assertTrue(underTest.isFaceLockoutErrorMsg(FACE_ERROR_LOCKOUT_PERMANENT))
+ assertFalse(underTest.isFaceLockoutErrorMsg(FACE_ERROR_TIMEOUT))
+ assertFalse(underTest.isFaceLockoutErrorMsg(FACE_ERROR_CANCELED))
+ assertFalse(underTest.isFaceLockoutErrorMsg(FACE_ERROR_UNABLE_TO_PROCESS))
+ assertFalse(underTest.isFaceLockoutErrorMsg(FACE_ERROR_VENDOR))
+ }
+
+ private fun givenPrimaryAuthNotRequired() {
+ whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean()))
+ .thenReturn(true)
+ }
+
+ private fun givenPrimaryAuthRequired() {
+ whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean()))
+ .thenReturn(false)
+ }
+}
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 48c3e2d85574..b1f5dde278be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -72,6 +72,7 @@ import android.content.Intent;
import android.content.pm.UserInfo;
import android.graphics.Color;
import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
@@ -98,14 +99,15 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.keyguard.util.IndicationHelper;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
@@ -213,6 +215,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private StatusBarStateController.StateListener mStatusBarStateListener;
private ScreenLifecycle.Observer mScreenObserver;
private BroadcastReceiver mBroadcastReceiver;
+ private IndicationHelper mIndicationHelper;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private TestableLooper mTestableLooper;
private final int mCurrentUserId = 1;
@@ -262,13 +265,14 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
-
when(mDevicePolicyResourcesManager.getString(anyString(), any()))
.thenReturn(mDisclosureGeneric);
when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
.thenReturn(mDisclosureWithOrganization);
when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
+ mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);
+
mWakeLock = new WakeLockFake();
mWakeLockBuilder = new WakeLockFake.Builder(mContext);
mWakeLockBuilder.setWakeLock(mWakeLock);
@@ -304,7 +308,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mAlarmManager,
mUserTracker,
mock(BouncerMessageInteractor.class),
- flags
+ flags,
+ mIndicationHelper
);
mController.init();
mController.setIndicationArea(mIndicationArea);
@@ -805,33 +810,19 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
}
@Test
- public void transientIndication_visibleWhenDozing_ignoresFingerprintCancellation() {
+ public void transientIndication_visibleWhenDozing_ignoresFingerprintErrorMsg() {
createController();
-
mController.setVisible(true);
reset(mRotateTextViewController);
- mController.getKeyguardCallback().onBiometricError(
- FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED, "foo",
- BiometricSourceType.FINGERPRINT);
- mController.getKeyguardCallback().onBiometricError(
- FingerprintManager.FINGERPRINT_ERROR_CANCELED, "bar",
- BiometricSourceType.FINGERPRINT);
- verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
- verifyNoMessage(INDICATION_TYPE_TRANSIENT);
- }
-
- @Test
- public void transientIndication_visibleWhenDozing_ignoresPowerPressed() {
- createController();
-
- mController.setVisible(true);
- reset(mRotateTextViewController);
+ // WHEN a fingerprint error user cancelled message is received
mController.getKeyguardCallback().onBiometricError(
- FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED, "foo",
+ BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED, "foo",
BiometricSourceType.FINGERPRINT);
+ // THEN no message is shown
verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+ verifyNoMessage(INDICATION_TYPE_TRANSIENT);
}
@Test