summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Beverly <beverlyt@google.com> 2024-03-06 19:49:56 +0000
committer Beverly <beverlyt@google.com> 2024-03-07 14:39:53 +0000
commit95f61def301e010f9577ba113c0995659a7a0dc7 (patch)
tree4aa64ea0a66d619b4b5eca436373f5f071285487
parent2966eb208c543cc50c1eab61111410c4306d6b3a (diff)
Don't show face messasges if there's a fp message showing (within 3.5s)
Test: atest AlternateBouncerMessageAreaViewModelTest Fixes: 327252680 Flag: ACONFIG com.android.systemui.device_entry_udfps_refactor STAGING Change-Id: Ib63346fc3e97922ca0fa5f9e42dc2a6bba58b172
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelTest.kt161
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModel.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt33
4 files changed, 220 insertions, 6 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelTest.kt
new file mode 100644
index 000000000000..87d1cd571e3c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelTest.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2024 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.ui.viewmodel
+
+import android.hardware.fingerprint.FingerprintManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.shared.model.FaceFailureMessage
+import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
+import com.android.systemui.deviceentry.shared.model.FingerprintFailureMessage
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AlternateBouncerMessageAreaViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val fingerprintAuthRepository by lazy {
+ kosmos.fakeDeviceEntryFingerprintAuthRepository
+ }
+ private val faceAuthRepository by lazy { kosmos.fakeDeviceEntryFaceAuthRepository }
+ private val bouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository }
+ private val biometricSettingsRepository by lazy { kosmos.fakeBiometricSettingsRepository }
+ private val underTest: AlternateBouncerMessageAreaViewModel =
+ kosmos.alternateBouncerMessageAreaViewModel
+
+ @Before
+ fun setUp() {
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
+ }
+
+ @Test
+ fun noInitialValue() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(true)
+ assertThat(message).isNull()
+ }
+
+ @Test
+ fun fingerprintMessage() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+ fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus)
+ assertThat(message).isInstanceOf(FingerprintFailureMessage::class.java)
+ }
+
+ @Test
+ fun fingerprintLockoutMessage_notShown() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+ fingerprintAuthRepository.setAuthenticationStatus(
+ ErrorFingerprintAuthenticationStatus(
+ msgId = FingerprintManager.FINGERPRINT_ERROR_LOCKOUT,
+ msg = "test lockout",
+ )
+ )
+ assertThat(message).isNull()
+ }
+
+ @Test
+ fun alternateBouncerNotVisible_messagesNeverShow() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(false)
+ runCurrent()
+ fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus)
+ assertThat(message).isNull()
+
+ faceAuthRepository.setAuthenticationStatus(FailedFaceAuthenticationStatus())
+ assertThat(message).isNull()
+ }
+
+ @Test
+ fun faceFailMessage() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+ faceAuthRepository.setAuthenticationStatus(FailedFaceAuthenticationStatus())
+ assertThat(message).isInstanceOf(FaceFailureMessage::class.java)
+ }
+
+ @Test
+ fun faceThenFingerprintMessage() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+ faceAuthRepository.setAuthenticationStatus(FailedFaceAuthenticationStatus())
+ assertThat(message).isInstanceOf(FaceFailureMessage::class.java)
+
+ fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus)
+ assertThat(message).isInstanceOf(FingerprintFailureMessage::class.java)
+ }
+
+ @Test
+ fun fingerprintMessagePreventsFaceMessageFromShowing() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+ fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus)
+ assertThat(message).isInstanceOf(FingerprintFailureMessage::class.java)
+
+ faceAuthRepository.setAuthenticationStatus(FailedFaceAuthenticationStatus())
+ assertThat(message).isInstanceOf(FingerprintFailureMessage::class.java)
+ }
+
+ @Test
+ fun fingerprintMessageAllowsFaceMessageAfter4000ms() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+ fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus)
+ assertThat(message).isInstanceOf(FingerprintFailureMessage::class.java)
+
+ advanceTimeBy(4000)
+
+ faceAuthRepository.setAuthenticationStatus(FailedFaceAuthenticationStatus())
+ assertThat(message).isInstanceOf(FaceFailureMessage::class.java)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModel.kt
index 9edb4d159d4a..bbe5fedbf12f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModel.kt
@@ -23,13 +23,19 @@ import com.android.systemui.deviceentry.shared.model.FaceMessage
import com.android.systemui.deviceentry.shared.model.FaceTimeoutMessage
import com.android.systemui.deviceentry.shared.model.FingerprintLockoutMessage
import com.android.systemui.deviceentry.shared.model.FingerprintMessage
+import com.android.systemui.statusbar.KeyguardIndicationController.DEFAULT_MESSAGE_TIME
+import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onStart
/** View model for the alternate bouncer message area. */
@ExperimentalCoroutinesApi
@@ -38,19 +44,32 @@ class AlternateBouncerMessageAreaViewModel
constructor(
biometricMessageInteractor: BiometricMessageInteractor,
alternateBouncerInteractor: AlternateBouncerInteractor,
+ systemClock: com.android.systemui.util.time.SystemClock,
) {
-
- private val faceMessage: Flow<FaceMessage> =
- biometricMessageInteractor.faceMessage.filterNot { it is FaceTimeoutMessage }
+ private val fingerprintMessageWithTimestamp: Flow<Pair<FingerprintMessage?, Long>> =
+ biometricMessageInteractor.fingerprintMessage
+ .filterNot { it is FingerprintLockoutMessage }
+ .map { Pair(it, systemClock.uptimeMillis()) }
+ .filterIsInstance<Pair<FingerprintMessage?, Long>>()
+ .onStart { emit(Pair(null, -3500L)) }
private val fingerprintMessage: Flow<FingerprintMessage> =
- biometricMessageInteractor.fingerprintMessage.filterNot { it is FingerprintLockoutMessage }
+ fingerprintMessageWithTimestamp.filter { it.first != null }.map { it.first!! }
+ private val faceMessage: Flow<FaceMessage> =
+ biometricMessageInteractor.faceMessage
+ .filterNot { it is FaceTimeoutMessage }
+ // Don't show face messages if within the default message time for fp messages to show
+ .sample(fingerprintMessageWithTimestamp, ::Pair)
+ .filter { (_, fpMessage) ->
+ (systemClock.uptimeMillis() - fpMessage.second) >= DEFAULT_MESSAGE_TIME
+ }
+ .map { (faceMsg, _) -> faceMsg }
val message: Flow<BiometricMessage?> =
alternateBouncerInteractor.isVisible.flatMapLatest { isVisible ->
if (isVisible) {
merge(
- faceMessage,
fingerprintMessage,
+ faceMessage,
)
} else {
flowOf(null)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 1ec86aea49d8..c9046217e68a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -147,8 +147,9 @@ public class KeyguardIndicationController {
private static final int MSG_SHOW_ACTION_TO_UNLOCK = 1;
private static final int MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON = 2;
private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
+ public static final long DEFAULT_MESSAGE_TIME = 3500;
public static final long DEFAULT_HIDE_DELAY_MS =
- 3500 + KeyguardIndicationTextView.Y_IN_DURATION;
+ DEFAULT_MESSAGE_TIME + KeyguardIndicationTextView.Y_IN_DURATION;
private final Context mContext;
private final BroadcastDispatcher mBroadcastDispatcher;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt
new file mode 100644
index 000000000000..b7d9676040d0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.ui.viewmodel
+
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.deviceentry.domain.interactor.biometricMessageInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.time.systemClock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.alternateBouncerMessageAreaViewModel by
+ Kosmos.Fixture {
+ AlternateBouncerMessageAreaViewModel(
+ biometricMessageInteractor = biometricMessageInteractor,
+ alternateBouncerInteractor = alternateBouncerInteractor,
+ systemClock = systemClock,
+ )
+ }