Merge "Move all bouncer messages domain logic to the interactor" into main
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 21960e2..83b1a2c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -67,42 +67,6 @@
int PROMPT_REASON_TRUSTAGENT_EXPIRED = 8;
/**
- * Prompt that is shown when there is an incorrect primary authentication input.
- */
- int PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT = 9;
-
- /**
- * Prompt that is shown when there is an incorrect face biometric input.
- */
- int PROMPT_REASON_INCORRECT_FACE_INPUT = 10;
-
- /**
- * Prompt that is shown when there is an incorrect fingerprint biometric input.
- */
- int PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT = 11;
-
- /**
- * Prompt that is shown when face authentication is in locked out state.
- */
- int PROMPT_REASON_FACE_LOCKED_OUT = 12;
-
- /**
- * Prompt that is shown when fingerprint authentication is in locked out state.
- */
- int PROMPT_REASON_FINGERPRINT_LOCKED_OUT = 13;
-
- /**
- * Default prompt that is shown on the bouncer.
- */
- int PROMPT_REASON_DEFAULT = 14;
-
- /**
- * Prompt that is shown when primary authentication is in locked out state after too many
- * attempts
- */
- int PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT = 15;
-
- /**
* Strong auth is required because the device has just booted because of an automatic
* mainline update.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
deleted file mode 100644
index f93337c..0000000
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * 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.bouncer.data.factory
-
-import android.annotation.IntDef
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FACE_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FINGERPRINT_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FACE_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
-import com.android.systemui.res.R.string.bouncer_face_not_recognized
-import com.android.systemui.res.R.string.keyguard_enter_password
-import com.android.systemui.res.R.string.keyguard_enter_pattern
-import com.android.systemui.res.R.string.keyguard_enter_pin
-import com.android.systemui.res.R.string.kg_bio_too_many_attempts_password
-import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pattern
-import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pin
-import com.android.systemui.res.R.string.kg_bio_try_again_or_password
-import com.android.systemui.res.R.string.kg_bio_try_again_or_pattern
-import com.android.systemui.res.R.string.kg_bio_try_again_or_pin
-import com.android.systemui.res.R.string.kg_face_locked_out
-import com.android.systemui.res.R.string.kg_fp_locked_out
-import com.android.systemui.res.R.string.kg_fp_not_recognized
-import com.android.systemui.res.R.string.kg_primary_auth_locked_out_password
-import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pattern
-import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pin
-import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
-import com.android.systemui.res.R.string.kg_prompt_after_update_password
-import com.android.systemui.res.R.string.kg_prompt_after_update_pattern
-import com.android.systemui.res.R.string.kg_prompt_after_update_pin
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_password
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pattern
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pin
-import com.android.systemui.res.R.string.kg_prompt_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_password_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_pattern_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_pin_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_password
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_pattern
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_pin
-import com.android.systemui.res.R.string.kg_prompt_unattended_update
-import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
-import com.android.systemui.res.R.string.kg_trust_agent_disabled
-import com.android.systemui.res.R.string.kg_unlock_with_password_or_fp
-import com.android.systemui.res.R.string.kg_unlock_with_pattern_or_fp
-import com.android.systemui.res.R.string.kg_unlock_with_pin_or_fp
-import com.android.systemui.res.R.string.kg_wrong_input_try_fp_suggestion
-import com.android.systemui.res.R.string.kg_wrong_password_try_again
-import com.android.systemui.res.R.string.kg_wrong_pattern_try_again
-import com.android.systemui.res.R.string.kg_wrong_pin_try_again
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.bouncer.shared.model.Message
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
-import javax.inject.Inject
-
-@SysUISingleton
-class BouncerMessageFactory
-@Inject
-constructor(
- private val biometricSettingsRepository: BiometricSettingsRepository,
- private val securityModel: KeyguardSecurityModel,
-) {
-
- fun createFromPromptReason(
- @BouncerPromptReason reason: Int,
- userId: Int,
- secondaryMsgOverride: String? = null
- ): BouncerMessageModel? {
- val pair =
- getBouncerMessage(
- reason,
- securityModel.getSecurityMode(userId),
- biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value
- )
- return pair?.let {
- BouncerMessageModel(
- message = Message(messageResId = pair.first, animate = false),
- secondaryMessage =
- secondaryMsgOverride?.let {
- Message(message = secondaryMsgOverride, animate = false)
- }
- ?: Message(messageResId = pair.second, animate = false)
- )
- }
- }
-
- /**
- * Helper method that provides the relevant bouncer message that should be shown for different
- * scenarios indicated by [reason]. [securityMode] & [fpAuthIsAllowed] parameters are used to
- * provide a more specific message.
- */
- private fun getBouncerMessage(
- @BouncerPromptReason reason: Int,
- securityMode: SecurityMode,
- fpAuthIsAllowed: Boolean = false
- ): Pair<Int, Int>? {
- return when (reason) {
- // Primary auth locked out
- PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT -> primaryAuthLockedOut(securityMode)
- // Primary auth required reasons
- PROMPT_REASON_RESTART -> authRequiredAfterReboot(securityMode)
- PROMPT_REASON_TIMEOUT -> authRequiredAfterPrimaryAuthTimeout(securityMode)
- PROMPT_REASON_DEVICE_ADMIN -> authRequiredAfterAdminLockdown(securityMode)
- PROMPT_REASON_USER_REQUEST -> authRequiredAfterUserLockdown(securityMode)
- PROMPT_REASON_PREPARE_FOR_UPDATE -> authRequiredForUnattendedUpdate(securityMode)
- PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE -> authRequiredForMainlineUpdate(securityMode)
- PROMPT_REASON_FINGERPRINT_LOCKED_OUT -> fingerprintUnlockUnavailable(securityMode)
- PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode)
- // Non strong auth not available reasons
- PROMPT_REASON_FACE_LOCKED_OUT ->
- if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode)
- else faceLockedOut(securityMode)
- PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT ->
- if (fpAuthIsAllowed) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
- else nonStrongAuthTimeout(securityMode)
- PROMPT_REASON_TRUSTAGENT_EXPIRED ->
- if (fpAuthIsAllowed) trustAgentDisabledWithFingerprintAllowed(securityMode)
- else trustAgentDisabled(securityMode)
- // Auth incorrect input reasons.
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT ->
- if (fpAuthIsAllowed) incorrectSecurityInputWithFingerprint(securityMode)
- else incorrectSecurityInput(securityMode)
- PROMPT_REASON_INCORRECT_FACE_INPUT ->
- if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode)
- else incorrectFaceInput(securityMode)
- PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT -> incorrectFingerprintInput(securityMode)
- // Default message
- PROMPT_REASON_DEFAULT ->
- if (fpAuthIsAllowed) defaultMessageWithFingerprint(securityMode)
- else defaultMessage(securityMode)
- else -> null
- }
- }
-
- fun emptyMessage(): BouncerMessageModel =
- BouncerMessageModel(Message(message = ""), Message(message = ""))
-}
-
-@Retention(AnnotationRetention.SOURCE)
-@IntDef(
- PROMPT_REASON_TIMEOUT,
- PROMPT_REASON_DEVICE_ADMIN,
- PROMPT_REASON_USER_REQUEST,
- PROMPT_REASON_AFTER_LOCKOUT,
- PROMPT_REASON_PREPARE_FOR_UPDATE,
- PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT,
- PROMPT_REASON_TRUSTAGENT_EXPIRED,
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- PROMPT_REASON_INCORRECT_FACE_INPUT,
- PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT,
- PROMPT_REASON_FACE_LOCKED_OUT,
- PROMPT_REASON_FINGERPRINT_LOCKED_OUT,
- PROMPT_REASON_DEFAULT,
- PROMPT_REASON_NONE,
- PROMPT_REASON_RESTART,
- PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT,
- PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE,
-)
-annotation class BouncerPromptReason
-
-private fun defaultMessage(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, 0)
- SecurityMode.Password -> Pair(keyguard_enter_password, 0)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, 0)
- else -> Pair(0, 0)
- }
-}
-
-private fun defaultMessageWithFingerprint(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, 0)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, 0)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, 0)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectSecurityInput(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, 0)
- SecurityMode.Password -> Pair(kg_wrong_password_try_again, 0)
- SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, 0)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectSecurityInputWithFingerprint(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, kg_wrong_input_try_fp_suggestion)
- SecurityMode.Password -> Pair(kg_wrong_password_try_again, kg_wrong_input_try_fp_suggestion)
- SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, kg_wrong_input_try_fp_suggestion)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectFingerprintInput(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pattern)
- SecurityMode.Password -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_password)
- SecurityMode.PIN -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectFaceInput(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pattern)
- SecurityMode.Password -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_password)
- SecurityMode.PIN -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectFaceInputWithFingerprintAllowed(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, bouncer_face_not_recognized)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, bouncer_face_not_recognized)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, bouncer_face_not_recognized)
- else -> Pair(0, 0)
- }
-}
-
-private fun biometricLockout(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterReboot(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_reason_restart_pattern)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_reason_restart_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterAdminLockdown(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_dpm_lock)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_dpm_lock)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterUserLockdown(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
- SecurityMode.Password ->
- Pair(keyguard_enter_password, kg_prompt_after_user_lockdown_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_unattended_update)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_unattended_update)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_unattended_update)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredForMainlineUpdate(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_update_pattern)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_update_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_update_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_password_auth_timeout)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout)
- else -> Pair(0, 0)
- }
-}
-
-private fun nonStrongAuthTimeout(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_auth_timeout)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_auth_timeout)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_auth_timeout)
- else -> Pair(0, 0)
- }
-}
-
-private fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_prompt_auth_timeout)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_prompt_auth_timeout)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_auth_timeout)
- else -> Pair(0, 0)
- }
-}
-
-private fun faceLockedOut(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_face_locked_out)
- else -> Pair(0, 0)
- }
-}
-
-private fun faceLockedOutButFingerprintAvailable(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_face_locked_out)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_face_locked_out)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_face_locked_out)
- else -> Pair(0, 0)
- }
-}
-
-private fun fingerprintUnlockUnavailable(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_fp_locked_out)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_fp_locked_out)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_fp_locked_out)
- else -> Pair(0, 0)
- }
-}
-
-private fun trustAgentDisabled(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_trust_agent_disabled)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_trust_agent_disabled)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_trust_agent_disabled)
- else -> Pair(0, 0)
- }
-}
-
-private fun trustAgentDisabledWithFingerprintAllowed(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_trust_agent_disabled)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_trust_agent_disabled)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_trust_agent_disabled)
- else -> Pair(0, 0)
- }
-}
-
-private fun primaryAuthLockedOut(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern ->
- Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pattern)
- SecurityMode.Password ->
- Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_password)
- SecurityMode.PIN ->
- Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pin)
- else -> Pair(0, 0)
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
index 97c1bdb..094dc0a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
@@ -16,315 +16,26 @@
package com.android.systemui.bouncer.data.repository
-import android.hardware.biometrics.BiometricSourceType
-import android.hardware.biometrics.BiometricSourceType.FACE
-import android.hardware.biometrics.BiometricSourceType.FINGERPRINT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FACE_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FINGERPRINT_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FACE_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.SystemPropertiesHelper
-import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.TrustRepository
-import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onStart
/** Provide different sources of messages that needs to be shown on the bouncer. */
interface BouncerMessageRepository {
- /**
- * Messages that are shown in response to the incorrect security attempts on the bouncer and
- * primary authentication method being locked out, along with countdown messages before primary
- * auth is active again.
- */
- val primaryAuthMessage: Flow<BouncerMessageModel?>
+ val bouncerMessage: Flow<BouncerMessageModel>
- /**
- * Help messages that are shown to the user on how to successfully perform authentication using
- * face.
- */
- val faceAcquisitionMessage: Flow<BouncerMessageModel?>
-
- /**
- * Help messages that are shown to the user on how to successfully perform authentication using
- * fingerprint.
- */
- val fingerprintAcquisitionMessage: Flow<BouncerMessageModel?>
-
- /** Custom message that is displayed when the bouncer is being shown to launch an app. */
- val customMessage: Flow<BouncerMessageModel?>
-
- /**
- * Messages that are shown in response to biometric authentication attempts through face or
- * fingerprint.
- */
- val biometricAuthMessage: Flow<BouncerMessageModel?>
-
- /** Messages that are shown when certain auth flags are set. */
- val authFlagsMessage: Flow<BouncerMessageModel?>
-
- /** Messages that are show after biometrics are locked out temporarily or permanently */
- val biometricLockedOutMessage: Flow<BouncerMessageModel?>
-
- /** Set the value for [primaryAuthMessage] */
- fun setPrimaryAuthMessage(value: BouncerMessageModel?)
-
- /** Set the value for [faceAcquisitionMessage] */
- fun setFaceAcquisitionMessage(value: BouncerMessageModel?)
- /** Set the value for [fingerprintAcquisitionMessage] */
- fun setFingerprintAcquisitionMessage(value: BouncerMessageModel?)
-
- /** Set the value for [customMessage] */
- fun setCustomMessage(value: BouncerMessageModel?)
-
- /**
- * Clear any previously set messages for [primaryAuthMessage], [faceAcquisitionMessage],
- * [fingerprintAcquisitionMessage] & [customMessage]
- */
- fun clearMessage()
+ fun setMessage(message: BouncerMessageModel)
}
-private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last"
-private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"
-
@SysUISingleton
-class BouncerMessageRepositoryImpl
-@Inject
-constructor(
- trustRepository: TrustRepository,
- biometricSettingsRepository: BiometricSettingsRepository,
- updateMonitor: KeyguardUpdateMonitor,
- private val bouncerMessageFactory: BouncerMessageFactory,
- private val userRepository: UserRepository,
- private val systemPropertiesHelper: SystemPropertiesHelper,
- fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
-) : BouncerMessageRepository {
+class BouncerMessageRepositoryImpl @Inject constructor() : BouncerMessageRepository {
- private val isAnyBiometricsEnabledAndEnrolled =
- or(
- biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
- biometricSettingsRepository.isFingerprintEnrolledAndEnabled,
- )
+ private val _bouncerMessage = MutableStateFlow(BouncerMessageModel())
+ override val bouncerMessage: Flow<BouncerMessageModel> = _bouncerMessage
- private val wasRebootedForMainlineUpdate
- get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
-
- private val authFlagsBasedPromptReason: Flow<Int> =
- combine(
- biometricSettingsRepository.authenticationFlags,
- trustRepository.isCurrentUserTrustManaged,
- isAnyBiometricsEnabledAndEnrolled,
- ::Triple
- )
- .map { (flags, isTrustManaged, biometricsEnrolledAndEnabled) ->
- val trustOrBiometricsAvailable = (isTrustManaged || biometricsEnrolledAndEnabled)
- return@map if (
- trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot
- ) {
- if (wasRebootedForMainlineUpdate) PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
- else PROMPT_REASON_RESTART
- } else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) {
- PROMPT_REASON_TIMEOUT
- } else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) {
- PROMPT_REASON_DEVICE_ADMIN
- } else if (isTrustManaged && flags.someAuthRequiredAfterUserRequest) {
- PROMPT_REASON_TRUSTAGENT_EXPIRED
- } else if (isTrustManaged && flags.someAuthRequiredAfterTrustAgentExpired) {
- PROMPT_REASON_TRUSTAGENT_EXPIRED
- } else if (trustOrBiometricsAvailable && flags.isInUserLockdown) {
- PROMPT_REASON_USER_REQUEST
- } else if (
- trustOrBiometricsAvailable && flags.primaryAuthRequiredForUnattendedUpdate
- ) {
- PROMPT_REASON_PREPARE_FOR_UPDATE
- } else if (
- trustOrBiometricsAvailable &&
- flags.strongerAuthRequiredAfterNonStrongBiometricsTimeout
- ) {
- PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
- } else {
- PROMPT_REASON_NONE
- }
- }
-
- private val biometricAuthReason: Flow<Int> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardUpdateMonitorCallback() {
- override fun onBiometricAuthFailed(
- biometricSourceType: BiometricSourceType?
- ) {
- val promptReason =
- if (biometricSourceType == FINGERPRINT)
- PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT
- else if (
- biometricSourceType == FACE && !updateMonitor.isFaceLockedOut
- ) {
- PROMPT_REASON_INCORRECT_FACE_INPUT
- } else PROMPT_REASON_NONE
- trySendWithFailureLogging(promptReason, TAG, "onBiometricAuthFailed")
- }
-
- override fun onBiometricsCleared() {
- trySendWithFailureLogging(
- PROMPT_REASON_NONE,
- TAG,
- "onBiometricsCleared"
- )
- }
-
- override fun onBiometricAcquired(
- biometricSourceType: BiometricSourceType?,
- acquireInfo: Int
- ) {
- trySendWithFailureLogging(
- PROMPT_REASON_NONE,
- TAG,
- "clearBiometricPrompt for new auth session."
- )
- }
-
- override fun onBiometricAuthenticated(
- userId: Int,
- biometricSourceType: BiometricSourceType?,
- isStrongBiometric: Boolean
- ) {
- trySendWithFailureLogging(
- PROMPT_REASON_NONE,
- TAG,
- "onBiometricAuthenticated"
- )
- }
- }
- updateMonitor.registerCallback(callback)
- awaitClose { updateMonitor.removeCallback(callback) }
- }
- .distinctUntilChanged()
-
- private val _primaryAuthMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val primaryAuthMessage: Flow<BouncerMessageModel?> = _primaryAuthMessage
-
- private val _faceAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val faceAcquisitionMessage: Flow<BouncerMessageModel?> = _faceAcquisitionMessage
-
- private val _fingerprintAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val fingerprintAcquisitionMessage: Flow<BouncerMessageModel?> =
- _fingerprintAcquisitionMessage
-
- private val _customMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val customMessage: Flow<BouncerMessageModel?> = _customMessage
-
- override val biometricAuthMessage: Flow<BouncerMessageModel?> =
- biometricAuthReason
- .map {
- if (it == PROMPT_REASON_NONE) null
- else
- bouncerMessageFactory.createFromPromptReason(
- it,
- userRepository.getSelectedUserInfo().id
- )
- }
- .onStart { emit(null) }
- .distinctUntilChanged()
-
- override val authFlagsMessage: Flow<BouncerMessageModel?> =
- authFlagsBasedPromptReason
- .map {
- if (it == PROMPT_REASON_NONE) null
- else
- bouncerMessageFactory.createFromPromptReason(
- it,
- userRepository.getSelectedUserInfo().id
- )
- }
- .onStart { emit(null) }
- .distinctUntilChanged()
-
- // TODO (b/262838215): Replace with DeviceEntryFaceAuthRepository when the new face auth system
- // has been launched.
- private val faceLockedOut: Flow<Boolean> = conflatedCallbackFlow {
- val callback =
- object : KeyguardUpdateMonitorCallback() {
- override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType?) {
- if (biometricSourceType == FACE) {
- trySendWithFailureLogging(
- updateMonitor.isFaceLockedOut,
- TAG,
- "face lock out state changed."
- )
- }
- }
- }
- updateMonitor.registerCallback(callback)
- trySendWithFailureLogging(updateMonitor.isFaceLockedOut, TAG, "face lockout initial value")
- awaitClose { updateMonitor.removeCallback(callback) }
- }
-
- override val biometricLockedOutMessage: Flow<BouncerMessageModel?> =
- combine(fingerprintAuthRepository.isLockedOut, faceLockedOut) { fp, face ->
- return@combine if (fp) {
- bouncerMessageFactory.createFromPromptReason(
- PROMPT_REASON_FINGERPRINT_LOCKED_OUT,
- userRepository.getSelectedUserInfo().id
- )
- } else if (face) {
- bouncerMessageFactory.createFromPromptReason(
- PROMPT_REASON_FACE_LOCKED_OUT,
- userRepository.getSelectedUserInfo().id
- )
- } else null
- }
-
- override fun setPrimaryAuthMessage(value: BouncerMessageModel?) {
- _primaryAuthMessage.value = value
- }
-
- override fun setFaceAcquisitionMessage(value: BouncerMessageModel?) {
- _faceAcquisitionMessage.value = value
- }
-
- override fun setFingerprintAcquisitionMessage(value: BouncerMessageModel?) {
- _fingerprintAcquisitionMessage.value = value
- }
-
- override fun setCustomMessage(value: BouncerMessageModel?) {
- _customMessage.value = value
- }
-
- override fun clearMessage() {
- _fingerprintAcquisitionMessage.value = null
- _faceAcquisitionMessage.value = null
- _primaryAuthMessage.value = null
- _customMessage.value = null
- }
-
- companion object {
- const val TAG = "BouncerDetailedMessageRepository"
+ override fun setMessage(message: BouncerMessageModel) {
+ _bouncerMessage.value = message
}
}
-
-private fun or(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) =
- flow.combine(anotherFlow) { a, b -> a || b }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
index 497747f..aecfe1d2 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
@@ -16,16 +16,13 @@
package com.android.systemui.bouncer.domain.interactor
-import android.os.Build
import android.util.Log
import com.android.systemui.CoreStartable
import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
private val TAG = BouncerMessageAuditLogger::class.simpleName!!
@@ -37,24 +34,8 @@
constructor(
@Application private val scope: CoroutineScope,
private val repository: BouncerMessageRepository,
- private val interactor: BouncerMessageInteractor,
) : CoreStartable {
override fun start() {
- if (Build.isDebuggable()) {
- collectAndLog(repository.biometricAuthMessage, "biometricMessage: ")
- collectAndLog(repository.primaryAuthMessage, "primaryAuthMessage: ")
- collectAndLog(repository.customMessage, "customMessage: ")
- collectAndLog(repository.faceAcquisitionMessage, "faceAcquisitionMessage: ")
- collectAndLog(
- repository.fingerprintAcquisitionMessage,
- "fingerprintAcquisitionMessage: "
- )
- collectAndLog(repository.authFlagsMessage, "authFlagsMessage: ")
- collectAndLog(interactor.bouncerMessage, "interactor.bouncerMessage: ")
- }
- }
-
- private fun collectAndLog(flow: Flow<BouncerMessageModel?>, context: String) {
- scope.launch { flow.collect { Log.d(TAG, context + it) } }
+ scope.launch { repository.bouncerMessage.collect { Log.d(TAG, "bouncerMessage: $it") } }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index fe01d08..f612f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -16,55 +16,234 @@
package com.android.systemui.bouncer.domain.interactor
+import android.hardware.biometrics.BiometricSourceType
import android.os.CountDownTimer
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.biometrics.data.repository.FacePropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES
+import com.android.systemui.flags.SystemPropertiesHelper
+import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
+import com.android.systemui.res.R.string.bouncer_face_not_recognized
+import com.android.systemui.res.R.string.keyguard_enter_password
+import com.android.systemui.res.R.string.keyguard_enter_pattern
+import com.android.systemui.res.R.string.keyguard_enter_pin
+import com.android.systemui.res.R.string.kg_bio_too_many_attempts_password
+import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pattern
+import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pin
+import com.android.systemui.res.R.string.kg_bio_try_again_or_password
+import com.android.systemui.res.R.string.kg_bio_try_again_or_pattern
+import com.android.systemui.res.R.string.kg_bio_try_again_or_pin
+import com.android.systemui.res.R.string.kg_face_locked_out
+import com.android.systemui.res.R.string.kg_fp_not_recognized
+import com.android.systemui.res.R.string.kg_primary_auth_locked_out_password
+import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pattern
+import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pin
+import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
+import com.android.systemui.res.R.string.kg_prompt_after_update_password
+import com.android.systemui.res.R.string.kg_prompt_after_update_pattern
+import com.android.systemui.res.R.string.kg_prompt_after_update_pin
+import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_password
+import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pattern
+import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pin
+import com.android.systemui.res.R.string.kg_prompt_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_password_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_pattern_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_pin_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_reason_restart_password
+import com.android.systemui.res.R.string.kg_prompt_reason_restart_pattern
+import com.android.systemui.res.R.string.kg_prompt_reason_restart_pin
+import com.android.systemui.res.R.string.kg_prompt_unattended_update
+import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
+import com.android.systemui.res.R.string.kg_trust_agent_disabled
+import com.android.systemui.res.R.string.kg_unlock_with_password_or_fp
+import com.android.systemui.res.R.string.kg_unlock_with_pattern_or_fp
+import com.android.systemui.res.R.string.kg_unlock_with_pin_or_fp
+import com.android.systemui.res.R.string.kg_wrong_input_try_fp_suggestion
+import com.android.systemui.res.R.string.kg_wrong_password_try_again
+import com.android.systemui.res.R.string.kg_wrong_pattern_try_again
+import com.android.systemui.res.R.string.kg_wrong_pin_try_again
import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.kotlin.Quint
import javax.inject.Inject
import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last"
+private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"
+private const val TAG = "BouncerMessageInteractor"
@SysUISingleton
class BouncerMessageInteractor
@Inject
constructor(
private val repository: BouncerMessageRepository,
- private val factory: BouncerMessageFactory,
private val userRepository: UserRepository,
private val countDownTimerUtil: CountDownTimerUtil,
private val featureFlags: FeatureFlags,
+ private val updateMonitor: KeyguardUpdateMonitor,
+ trustRepository: TrustRepository,
+ biometricSettingsRepository: BiometricSettingsRepository,
+ private val systemPropertiesHelper: SystemPropertiesHelper,
+ primaryBouncerInteractor: PrimaryBouncerInteractor,
+ @Application private val applicationScope: CoroutineScope,
+ private val facePropertyRepository: FacePropertyRepository,
+ deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ faceAuthRepository: DeviceEntryFaceAuthRepository,
+ private val securityModel: KeyguardSecurityModel,
) {
+
+ private val isFingerprintAuthCurrentlyAllowed =
+ deviceEntryFingerprintAuthRepository.isLockedOut
+ .isFalse()
+ .and(biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed)
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
+
+ private val currentSecurityMode
+ get() = securityModel.getSecurityMode(currentUserId)
+ private val currentUserId
+ get() = userRepository.getSelectedUserInfo().id
+
+ private val kumCallback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
+ repository.setMessage(
+ when (biometricSourceType) {
+ BiometricSourceType.FINGERPRINT ->
+ incorrectFingerprintInput(currentSecurityMode)
+ BiometricSourceType.FACE ->
+ incorrectFaceInput(
+ currentSecurityMode,
+ isFingerprintAuthCurrentlyAllowed.value
+ )
+ else ->
+ defaultMessage(
+ currentSecurityMode,
+ isFingerprintAuthCurrentlyAllowed.value
+ )
+ }
+ )
+ }
+
+ override fun onBiometricAcquired(
+ biometricSourceType: BiometricSourceType?,
+ acquireInfo: Int
+ ) {
+ super.onBiometricAcquired(biometricSourceType, acquireInfo)
+ }
+
+ override fun onBiometricAuthenticated(
+ userId: Int,
+ biometricSourceType: BiometricSourceType?,
+ isStrongBiometric: Boolean
+ ) {
+ repository.setMessage(defaultMessage)
+ }
+ }
+
+ private val isAnyBiometricsEnabledAndEnrolled =
+ biometricSettingsRepository.isFaceAuthEnrolledAndEnabled.or(
+ biometricSettingsRepository.isFingerprintEnrolledAndEnabled
+ )
+
+ private val wasRebootedForMainlineUpdate
+ get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
+
+ private val isFaceAuthClass3
+ get() = facePropertyRepository.sensorInfo.value?.strength == SensorStrength.STRONG
+
+ private val initialBouncerMessage: Flow<BouncerMessageModel> =
+ combine(
+ biometricSettingsRepository.authenticationFlags,
+ trustRepository.isCurrentUserTrustManaged,
+ isAnyBiometricsEnabledAndEnrolled,
+ deviceEntryFingerprintAuthRepository.isLockedOut,
+ faceAuthRepository.isLockedOut,
+ ::Quint
+ )
+ .map { (flags, _, biometricsEnrolledAndEnabled, fpLockedOut, faceLockedOut) ->
+ val isTrustUsuallyManaged = trustRepository.isCurrentUserTrustUsuallyManaged.value
+ val trustOrBiometricsAvailable =
+ (isTrustUsuallyManaged || biometricsEnrolledAndEnabled)
+ return@map if (
+ trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot
+ ) {
+ if (wasRebootedForMainlineUpdate) {
+ authRequiredForMainlineUpdate(currentSecurityMode)
+ } else {
+ authRequiredAfterReboot(currentSecurityMode)
+ }
+ } else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) {
+ authRequiredAfterPrimaryAuthTimeout(currentSecurityMode)
+ } else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) {
+ authRequiredAfterAdminLockdown(currentSecurityMode)
+ } else if (
+ trustOrBiometricsAvailable && flags.primaryAuthRequiredForUnattendedUpdate
+ ) {
+ authRequiredForUnattendedUpdate(currentSecurityMode)
+ } else if (fpLockedOut) {
+ class3AuthLockedOut(currentSecurityMode)
+ } else if (faceLockedOut) {
+ if (isFaceAuthClass3) {
+ class3AuthLockedOut(currentSecurityMode)
+ } else {
+ faceLockedOut(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+ }
+ } else if (
+ trustOrBiometricsAvailable &&
+ flags.strongerAuthRequiredAfterNonStrongBiometricsTimeout
+ ) {
+ nonStrongAuthTimeout(
+ currentSecurityMode,
+ isFingerprintAuthCurrentlyAllowed.value
+ )
+ } else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterUserRequest) {
+ trustAgentDisabled(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+ } else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterTrustAgentExpired) {
+ trustAgentDisabled(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+ } else if (trustOrBiometricsAvailable && flags.isInUserLockdown) {
+ authRequiredAfterUserLockdown(currentSecurityMode)
+ } else {
+ defaultMessage
+ }
+ }
+
fun onPrimaryAuthLockedOut(secondsBeforeLockoutReset: Long) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
val callback =
object : CountDownTimerCallback {
override fun onFinish() {
- repository.clearMessage()
+ repository.setMessage(defaultMessage)
}
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished / 1000.0).roundToInt()
- val message =
- factory.createFromPromptReason(
- reason = PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT,
- userId = userRepository.getSelectedUserInfo().id
- )
- message?.message?.animate = false
- message?.message?.formatterArgs =
+ val message = primaryAuthLockedOut(currentSecurityMode)
+ message.message?.animate = false
+ message.message?.formatterArgs =
mutableMapOf<String, Any>(Pair("count", secondsRemaining))
- repository.setPrimaryAuthMessage(message)
+ repository.setMessage(message)
}
}
countDownTimerUtil.startNewTimer(secondsBeforeLockoutReset * 1000, 1000, callback)
@@ -73,104 +252,58 @@
fun onPrimaryAuthIncorrectAttempt() {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
- repository.setPrimaryAuthMessage(
- factory.createFromPromptReason(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- userRepository.getSelectedUserInfo().id
- )
+ repository.setMessage(
+ incorrectSecurityInput(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
)
}
fun setFingerprintAcquisitionMessage(value: String?) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
-
- repository.setFingerprintAcquisitionMessage(
- if (value != null) {
- factory.createFromPromptReason(
- PROMPT_REASON_DEFAULT,
- userRepository.getSelectedUserInfo().id,
- secondaryMsgOverride = value
- )
- } else {
- null
- }
+ repository.setMessage(
+ defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
)
}
fun setFaceAcquisitionMessage(value: String?) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
-
- repository.setFaceAcquisitionMessage(
- if (value != null) {
- factory.createFromPromptReason(
- PROMPT_REASON_DEFAULT,
- userRepository.getSelectedUserInfo().id,
- secondaryMsgOverride = value
- )
- } else {
- null
- }
+ repository.setMessage(
+ defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
)
}
fun setCustomMessage(value: String?) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
- repository.setCustomMessage(
- if (value != null) {
- factory.createFromPromptReason(
- PROMPT_REASON_DEFAULT,
- userRepository.getSelectedUserInfo().id,
- secondaryMsgOverride = value
- )
- } else {
- null
- }
+ repository.setMessage(
+ defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
)
}
+ private val defaultMessage: BouncerMessageModel
+ get() = defaultMessage(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+
fun onPrimaryBouncerUserInput() {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
-
- repository.clearMessage()
+ repository.setMessage(defaultMessage)
}
- fun onBouncerBeingHidden() {
- if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
+ val bouncerMessage = repository.bouncerMessage
- repository.clearMessage()
+ init {
+ updateMonitor.registerCallback(kumCallback)
+
+ combine(primaryBouncerInteractor.isShowing, initialBouncerMessage) { showing, bouncerMessage
+ ->
+ if (showing) {
+ bouncerMessage
+ } else {
+ null
+ }
+ }
+ .filterNotNull()
+ .onEach { repository.setMessage(it) }
+ .launchIn(applicationScope)
}
-
- private fun firstNonNullMessage(
- oneMessageModel: Flow<BouncerMessageModel?>,
- anotherMessageModel: Flow<BouncerMessageModel?>
- ): Flow<BouncerMessageModel?> {
- return oneMessageModel.combine(anotherMessageModel) { a, b -> a ?: b }
- }
-
- // Null if feature flag is enabled which gets ignored always or empty bouncer message model that
- // always maps to an empty string.
- private fun nullOrEmptyMessage() =
- flowOf(
- if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null else factory.emptyMessage()
- )
-
- val bouncerMessage =
- listOf(
- nullOrEmptyMessage(),
- repository.primaryAuthMessage,
- repository.biometricAuthMessage,
- repository.fingerprintAcquisitionMessage,
- repository.faceAcquisitionMessage,
- repository.customMessage,
- repository.authFlagsMessage,
- repository.biometricLockedOutMessage,
- userRepository.selectedUserInfo.map {
- factory.createFromPromptReason(PROMPT_REASON_DEFAULT, it.id)
- },
- )
- .reduce(::firstNonNullMessage)
- .distinctUntilChanged()
}
interface CountDownTimerCallback {
@@ -199,3 +332,272 @@
.start()
}
}
+
+private fun Flow<Boolean>.or(anotherFlow: Flow<Boolean>) =
+ this.combine(anotherFlow) { a, b -> a || b }
+
+private fun Flow<Boolean>.and(anotherFlow: Flow<Boolean>) =
+ this.combine(anotherFlow) { a, b -> a && b }
+
+private fun Flow<Boolean>.isFalse() = this.map { !it }
+
+private fun defaultMessage(
+ securityMode: SecurityMode,
+ secondaryMessage: String?,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return BouncerMessageModel(
+ message =
+ Message(
+ messageResId = defaultMessage(securityMode, fpAuthIsAllowed).message?.messageResId,
+ animate = false
+ ),
+ secondaryMessage = Message(message = secondaryMessage, animate = false)
+ )
+}
+
+private fun defaultMessage(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) {
+ defaultMessageWithFingerprint(securityMode)
+ } else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, 0)
+ SecurityMode.Password -> Pair(keyguard_enter_password, 0)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, 0)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun defaultMessageWithFingerprint(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, 0)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, 0)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, 0)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectSecurityInput(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) {
+ incorrectSecurityInputWithFingerprint(securityMode)
+ } else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, 0)
+ SecurityMode.Password -> Pair(kg_wrong_password_try_again, 0)
+ SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, 0)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectSecurityInputWithFingerprint(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, kg_wrong_input_try_fp_suggestion)
+ SecurityMode.Password -> Pair(kg_wrong_password_try_again, kg_wrong_input_try_fp_suggestion)
+ SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, kg_wrong_input_try_fp_suggestion)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectFingerprintInput(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pattern)
+ SecurityMode.Password -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_password)
+ SecurityMode.PIN -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectFaceInput(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode)
+ else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pattern)
+ SecurityMode.Password -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_password)
+ SecurityMode.PIN -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectFaceInputWithFingerprintAllowed(
+ securityMode: SecurityMode
+): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, bouncer_face_not_recognized)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, bouncer_face_not_recognized)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, bouncer_face_not_recognized)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun biometricLockout(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterReboot(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_reason_restart_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_reason_restart_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterAdminLockdown(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_dpm_lock)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_dpm_lock)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterUserLockdown(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
+ SecurityMode.Password ->
+ Pair(keyguard_enter_password, kg_prompt_after_user_lockdown_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_unattended_update)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_unattended_update)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_unattended_update)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredForMainlineUpdate(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_update_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_update_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_update_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_password_auth_timeout)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun nonStrongAuthTimeout(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) {
+ nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
+ } else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_auth_timeout)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_auth_timeout)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_auth_timeout)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_prompt_auth_timeout)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_prompt_auth_timeout)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_auth_timeout)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun faceLockedOut(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode)
+ else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_face_locked_out)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun faceLockedOutButFingerprintAvailable(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_face_locked_out)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_face_locked_out)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_face_locked_out)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun class3AuthLockedOut(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun trustAgentDisabled(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) trustAgentDisabledWithFingerprintAllowed(securityMode)
+ else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_trust_agent_disabled)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_trust_agent_disabled)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_trust_agent_disabled)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun trustAgentDisabledWithFingerprintAllowed(
+ securityMode: SecurityMode
+): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_trust_agent_disabled)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_trust_agent_disabled)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_trust_agent_disabled)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun primaryAuthLockedOut(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pattern)
+ SecurityMode.Password ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_password)
+ SecurityMode.PIN ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun Pair<Int, Int>.toMessage(): BouncerMessageModel {
+ return BouncerMessageModel(
+ message = Message(messageResId = this.first, animate = false),
+ secondaryMessage = Message(messageResId = this.second, animate = false)
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
index 0e9e962..7b169f4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
@@ -22,7 +22,10 @@
* Represents the message displayed on the bouncer. It has two parts, primary and a secondary
* message
*/
-data class BouncerMessageModel(val message: Message? = null, val secondaryMessage: Message? = null)
+data class BouncerMessageModel(
+ val message: Message? = null,
+ val secondaryMessage: Message? = null,
+)
/**
* Representation of a single message on the bouncer. It can be either a string or a string resource
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index e29d6bd..36e5db4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -144,7 +144,6 @@
)
}
} else {
- bouncerMessageInteractor.onBouncerBeingHidden()
securityContainerController.onBouncerVisibilityChanged(
/* isVisible= */ false
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
index 00036ce..6522439 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
@@ -29,6 +29,7 @@
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
@@ -36,6 +37,8 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@@ -44,19 +47,25 @@
/** Encapsulates any state relevant to trust agents and trust grants. */
interface TrustRepository {
+ /** Flow representing whether the current user has enabled any trust agents. */
+ val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean>
+
/** Flow representing whether the current user is trusted. */
val isCurrentUserTrusted: Flow<Boolean>
/** Flow representing whether active unlock is running for the current user. */
val isCurrentUserActiveUnlockRunning: Flow<Boolean>
- /** Reports that whether trust is managed has changed for the current user. */
+ /**
+ * Reports whether a trust agent is currently enabled and managing the trust of the current user
+ */
val isCurrentUserTrustManaged: StateFlow<Boolean>
/** A trust agent is requesting to dismiss the keyguard from a trust change. */
val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
}
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class TrustRepositoryImpl
@Inject
@@ -174,6 +183,11 @@
}
.map { it!! }
+ override val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean> =
+ userRepository.selectedUserInfo
+ .flatMapLatest { flowOf(trustManager.isTrustUsuallyManaged(it.id)) }
+ .stateIn(applicationScope, started = SharingStarted.Eagerly, false)
+
private fun isUserTrustManaged(userId: Int) =
trustManagedForUser[userId]?.isTrustManaged ?: false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 98e5124..2f1b589 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -84,7 +84,6 @@
import com.android.keyguard.logging.KeyguardLogger;
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
-import com.android.systemui.res.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -103,6 +102,7 @@
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
@@ -1256,8 +1256,6 @@
if (biometricSourceType == FACE) {
mFaceAcquiredMessageDeferral.reset();
}
- mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
- mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
@Override
@@ -1278,8 +1276,6 @@
} else if (biometricSourceType == FINGERPRINT) {
onFingerprintAuthError(msgId, errString);
}
- mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
- mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
private void onFaceAuthError(int msgId, String errString) {
@@ -1351,8 +1347,6 @@
showActionToUnlock();
}
}
- mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
- mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
deleted file mode 100644
index 8eb274a..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.bouncer.data.factory
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Pattern
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.StringSubject
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class BouncerMessageFactoryTest : SysuiTestCase() {
- private lateinit var underTest: BouncerMessageFactory
-
- @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
-
- @Mock private lateinit var securityModel: KeyguardSecurityModel
-
- private lateinit var testScope: TestScope
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- testScope = TestScope()
- biometricSettingsRepository = FakeBiometricSettingsRepository()
- underTest = BouncerMessageFactory(biometricSettingsRepository, securityModel)
- }
-
- @Test
- fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAuthIsAllowed() =
- testScope.runTest {
- primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = false)
- .isEqualTo("Enter PIN")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = true)
- .isEqualTo("Unlock with PIN or fingerprint")
-
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = false)
- .isEqualTo("Enter password")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = true)
- .isEqualTo("Unlock with password or fingerprint")
-
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = false)
- .isEqualTo("Draw pattern")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = true)
- .isEqualTo("Unlock with pattern or fingerprint")
- }
-
- @Test
- fun bouncerMessages_overridesSecondaryMessageValue() =
- testScope.runTest {
- val bouncerMessageModel =
- bouncerMessageModel(
- PIN,
- true,
- PROMPT_REASON_DEFAULT,
- secondaryMessageOverride = "face acquisition message"
- )!!
- assertThat(context.resources.getString(bouncerMessageModel.message!!.messageResId!!))
- .isEqualTo("Unlock with PIN or fingerprint")
- assertThat(bouncerMessageModel.secondaryMessage!!.message!!)
- .isEqualTo("face acquisition message")
- }
-
- @Test
- fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAuthIsAllowed() =
- testScope.runTest {
- primaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = PIN,
- fpAuthAllowed = true
- )
- .isEqualTo("Wrong PIN. Try again.")
- secondaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = PIN,
- fpAuthAllowed = true
- )
- .isEqualTo("Or unlock with fingerprint")
-
- primaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Password,
- fpAuthAllowed = true
- )
- .isEqualTo("Wrong password. Try again.")
- secondaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Password,
- fpAuthAllowed = true
- )
- .isEqualTo("Or unlock with fingerprint")
-
- primaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Pattern,
- fpAuthAllowed = true
- )
- .isEqualTo("Wrong pattern. Try again.")
- secondaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Pattern,
- fpAuthAllowed = true
- )
- .isEqualTo("Or unlock with fingerprint")
- }
-
- private fun primaryMessage(
- reason: Int,
- mode: KeyguardSecurityModel.SecurityMode,
- fpAuthAllowed: Boolean
- ): StringSubject {
- return assertThat(
- context.resources.getString(
- bouncerMessageModel(mode, fpAuthAllowed, reason)!!.message!!.messageResId!!
- )
- )!!
- }
-
- private fun secondaryMessage(
- reason: Int,
- mode: KeyguardSecurityModel.SecurityMode,
- fpAuthAllowed: Boolean
- ): StringSubject {
- return assertThat(
- context.resources.getString(
- bouncerMessageModel(mode, fpAuthAllowed, reason)!!.secondaryMessage!!.messageResId!!
- )
- )!!
- }
-
- private fun bouncerMessageModel(
- mode: KeyguardSecurityModel.SecurityMode,
- fpAuthAllowed: Boolean,
- reason: Int,
- secondaryMessageOverride: String? = null,
- ): BouncerMessageModel? {
- whenever(securityModel.getSecurityMode(0)).thenReturn(mode)
- biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(fpAuthAllowed)
-
- return underTest.createFromPromptReason(
- reason,
- 0,
- secondaryMsgOverride = secondaryMessageOverride
- )
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
deleted file mode 100644
index f158b43..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * 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.bouncer.data.repo
-
-import android.content.pm.UserInfo
-import android.hardware.biometrics.BiometricSourceType
-import android.testing.TestableLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.res.R
-import com.android.systemui.res.R.string.keyguard_enter_pin
-import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pin
-import com.android.systemui.res.R.string.kg_prompt_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_pin_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_pin
-import com.android.systemui.res.R.string.kg_prompt_unattended_update
-import com.android.systemui.res.R.string.kg_trust_agent_disabled
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.bouncer.shared.model.Message
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.SystemPropertiesHelper
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.shared.model.AuthenticationFlags
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidJUnit4::class)
-class BouncerMessageRepositoryTest : SysuiTestCase() {
-
- @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
- @Mock private lateinit var securityModel: KeyguardSecurityModel
- @Mock private lateinit var systemPropertiesHelper: SystemPropertiesHelper
- @Captor
- private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
-
- private lateinit var underTest: BouncerMessageRepository
- private lateinit var trustRepository: FakeTrustRepository
- private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
- private lateinit var userRepository: FakeUserRepository
- private lateinit var fingerprintRepository: FakeDeviceEntryFingerprintAuthRepository
- private lateinit var testScope: TestScope
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- trustRepository = FakeTrustRepository()
- biometricSettingsRepository = FakeBiometricSettingsRepository()
- userRepository = FakeUserRepository()
- userRepository.setUserInfos(listOf(PRIMARY_USER))
- fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository()
- testScope = TestScope()
-
- biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
- whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
- underTest =
- BouncerMessageRepositoryImpl(
- trustRepository = trustRepository,
- biometricSettingsRepository = biometricSettingsRepository,
- updateMonitor = updateMonitor,
- bouncerMessageFactory =
- BouncerMessageFactory(biometricSettingsRepository, securityModel),
- userRepository = userRepository,
- fingerprintAuthRepository = fingerprintRepository,
- systemPropertiesHelper = systemPropertiesHelper
- )
- }
-
- @Test
- fun setCustomMessage_propagatesState() =
- testScope.runTest {
- underTest.setCustomMessage(message("not empty"))
-
- val customMessage = collectLastValue(underTest.customMessage)
-
- assertThat(customMessage()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun setFaceMessage_propagatesState() =
- testScope.runTest {
- underTest.setFaceAcquisitionMessage(message("not empty"))
-
- val faceAcquisitionMessage = collectLastValue(underTest.faceAcquisitionMessage)
-
- assertThat(faceAcquisitionMessage()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun setFpMessage_propagatesState() =
- testScope.runTest {
- underTest.setFingerprintAcquisitionMessage(message("not empty"))
-
- val fpAcquisitionMsg = collectLastValue(underTest.fingerprintAcquisitionMessage)
-
- assertThat(fpAcquisitionMsg()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun setPrimaryAuthMessage_propagatesState() =
- testScope.runTest {
- underTest.setPrimaryAuthMessage(message("not empty"))
-
- val primaryAuthMessage = collectLastValue(underTest.primaryAuthMessage)
-
- assertThat(primaryAuthMessage()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun biometricAuthMessage_propagatesBiometricAuthMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- val biometricAuthMessage = collectLastValue(underTest.biometricAuthMessage)
- runCurrent()
-
- verify(updateMonitor).registerCallback(updateMonitorCallback.capture())
-
- updateMonitorCallback.value.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT)
-
- assertThat(biometricAuthMessage())
- .isEqualTo(message(R.string.kg_fp_not_recognized, R.string.kg_bio_try_again_or_pin))
-
- updateMonitorCallback.value.onBiometricAuthFailed(BiometricSourceType.FACE)
-
- assertThat(biometricAuthMessage())
- .isEqualTo(
- message(R.string.bouncer_face_not_recognized, R.string.kg_bio_try_again_or_pin)
- )
-
- updateMonitorCallback.value.onBiometricAcquired(BiometricSourceType.FACE, 0)
-
- assertThat(biometricAuthMessage()).isNull()
- }
-
- @Test
- fun onFaceLockout_propagatesState() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- val lockoutMessage = collectLastValue(underTest.biometricLockedOutMessage)
- runCurrent()
- verify(updateMonitor).registerCallback(updateMonitorCallback.capture())
-
- whenever(updateMonitor.isFaceLockedOut).thenReturn(true)
- updateMonitorCallback.value.onLockedOutStateChanged(BiometricSourceType.FACE)
-
- assertThat(lockoutMessage())
- .isEqualTo(message(keyguard_enter_pin, R.string.kg_face_locked_out))
-
- whenever(updateMonitor.isFaceLockedOut).thenReturn(false)
- updateMonitorCallback.value.onLockedOutStateChanged(BiometricSourceType.FACE)
- assertThat(lockoutMessage()).isNull()
- }
-
- @Test
- fun onFingerprintLockout_propagatesState() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- val lockedOutMessage = collectLastValue(underTest.biometricLockedOutMessage)
- runCurrent()
-
- fingerprintRepository.setLockedOut(true)
-
- assertThat(lockedOutMessage())
- .isEqualTo(message(keyguard_enter_pin, R.string.kg_fp_locked_out))
-
- fingerprintRepository.setLockedOut(false)
- assertThat(lockedOutMessage()).isNull()
- }
-
- @Test
- fun onRestartForMainlineUpdate_shouldProvideRelevantMessage() =
- testScope.runTest {
- whenever(systemPropertiesHelper.get("sys.boot.reason.last"))
- .thenReturn("reboot,mainline_update")
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, R.string.kg_prompt_after_update_pin),
- )
- }
-
- @Test
- fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to null,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to null,
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to null,
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to null,
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to null,
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to null,
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- )
- }
-
- @Test
- fun authFlagsChanges_withTrustManaged_providesDifferentMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
-
- trustRepository.setCurrentUserTrustManaged(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin),
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout),
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
- Pair(keyguard_enter_pin, kg_trust_agent_disabled),
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
- Pair(keyguard_enter_pin, kg_trust_agent_disabled),
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
- Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin),
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
- Pair(keyguard_enter_pin, kg_prompt_unattended_update),
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_auth_timeout),
- )
- }
-
- @Test
- fun authFlagsChanges_withFaceEnrolled_providesDifferentMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
-
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to null,
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin),
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout),
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
- Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin),
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
- Pair(keyguard_enter_pin, kg_prompt_unattended_update),
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_auth_timeout),
- )
- }
-
- @Test
- fun authFlagsChanges_withFingerprintEnrolled_providesDifferentMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
-
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to null,
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin),
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout),
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
- Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin),
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
- Pair(keyguard_enter_pin, kg_prompt_unattended_update),
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_auth_timeout),
- )
- }
-
- private fun TestScope.verifyMessagesForAuthFlag(
- vararg authFlagToExpectedMessages: Pair<Int, Pair<Int, Int>?>
- ) {
- val authFlagsMessage = collectLastValue(underTest.authFlagsMessage)
-
- authFlagToExpectedMessages.forEach { (flag, messagePair) ->
- biometricSettingsRepository.setAuthenticationFlags(
- AuthenticationFlags(PRIMARY_USER_ID, flag)
- )
-
- assertThat(authFlagsMessage())
- .isEqualTo(messagePair?.let { message(it.first, it.second) })
- }
- }
-
- private fun message(primaryResId: Int, secondaryResId: Int): BouncerMessageModel {
- return BouncerMessageModel(
- message = Message(messageResId = primaryResId, animate = false),
- secondaryMessage = Message(messageResId = secondaryResId, animate = false)
- )
- }
- private fun message(value: String): BouncerMessageModel {
- return BouncerMessageModel(message = Message(message = value))
- }
-
- companion object {
- private const val PRIMARY_USER_ID = 0
- private val PRIMARY_USER =
- UserInfo(
- /* id= */ PRIMARY_USER_ID,
- /* name= */ "primary user",
- /* flags= */ UserInfo.FLAG_PRIMARY
- )
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index c1286a1..cc4eca5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -17,187 +17,216 @@
package com.android.systemui.bouncer.domain.interactor
import android.content.pm.UserInfo
+import android.os.Handler
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.widget.LockPatternUtils
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
-import com.android.systemui.res.R.string.kg_unlock_with_pin_or_fp
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.biometrics.data.repository.FaceSensorInfo
+import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.bouncer.shared.model.Message
-import com.android.systemui.coroutines.FlowValue
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.SystemPropertiesHelper
+import com.android.systemui.keyguard.DismissCallbackRegistry
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.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.shared.model.AuthenticationFlags
+import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
+import com.android.systemui.res.R.string.kg_trust_agent_disabled
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidJUnit4::class)
class BouncerMessageInteractorTest : SysuiTestCase() {
+ private val countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java)
+ private val repository = BouncerMessageRepositoryImpl()
+ private val userRepository = FakeUserRepository()
+ private val fakeTrustRepository = FakeTrustRepository()
+ private val fakeFacePropertyRepository = FakeFacePropertyRepository()
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val fakeDeviceEntryFingerprintAuthRepository =
+ FakeDeviceEntryFingerprintAuthRepository()
+ private val fakeDeviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
+ private val biometricSettingsRepository: FakeBiometricSettingsRepository =
+ FakeBiometricSettingsRepository()
+ @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var securityModel: KeyguardSecurityModel
- @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
@Mock private lateinit var countDownTimerUtil: CountDownTimerUtil
- private lateinit var countDownTimerCallback: KotlinArgumentCaptor<CountDownTimerCallback>
- private lateinit var underTest: BouncerMessageInteractor
- private lateinit var repository: FakeBouncerMessageRepository
- private lateinit var userRepository: FakeUserRepository
+ @Mock private lateinit var systemPropertiesHelper: SystemPropertiesHelper
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
private lateinit var testScope: TestScope
- private lateinit var bouncerMessage: FlowValue<BouncerMessageModel?>
+ private lateinit var underTest: BouncerMessageInteractor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- repository = FakeBouncerMessageRepository()
- userRepository = FakeUserRepository()
userRepository.setUserInfos(listOf(PRIMARY_USER))
testScope = TestScope()
- countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java)
- biometricSettingsRepository = FakeBiometricSettingsRepository()
-
allowTestableLooperAsMainThread()
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ overrideResource(kg_trust_agent_disabled, "Trust agent is unavailable")
}
suspend fun TestScope.init() {
userRepository.setSelectedUserInfo(PRIMARY_USER)
- val featureFlags = FakeFeatureFlags()
- featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
+ val featureFlags = FakeFeatureFlags().apply { set(Flags.REVAMPED_BOUNCER_MESSAGES, true) }
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ Mockito.mock(BouncerView::class.java),
+ Mockito.mock(Handler::class.java),
+ Mockito.mock(KeyguardStateController::class.java),
+ Mockito.mock(KeyguardSecurityModel::class.java),
+ Mockito.mock(PrimaryBouncerCallbackInteractor::class.java),
+ Mockito.mock(FalsingCollector::class.java),
+ Mockito.mock(DismissCallbackRegistry::class.java),
+ context,
+ keyguardUpdateMonitor,
+ fakeTrustRepository,
+ testScope.backgroundScope,
+ )
underTest =
BouncerMessageInteractor(
repository = repository,
- factory = BouncerMessageFactory(biometricSettingsRepository, securityModel),
userRepository = userRepository,
countDownTimerUtil = countDownTimerUtil,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ updateMonitor = updateMonitor,
+ biometricSettingsRepository = biometricSettingsRepository,
+ applicationScope = this.backgroundScope,
+ trustRepository = fakeTrustRepository,
+ systemPropertiesHelper = systemPropertiesHelper,
+ primaryBouncerInteractor = primaryBouncerInteractor,
+ facePropertyRepository = fakeFacePropertyRepository,
+ deviceEntryFingerprintAuthRepository = fakeDeviceEntryFingerprintAuthRepository,
+ faceAuthRepository = fakeDeviceEntryFaceAuthRepository,
+ securityModel = securityModel
)
- bouncerMessage = collectLastValue(underTest.bouncerMessage)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ bouncerRepository.setPrimaryShow(true)
+ runCurrent()
}
@Test
- fun onIncorrectSecurityInput_setsTheBouncerModelInTheRepository() =
+ fun onIncorrectSecurityInput_providesTheAppropriateValueForBouncerMessage() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.onPrimaryAuthIncorrectAttempt()
- assertThat(repository.primaryAuthMessage).isNotNull()
- assertThat(
- context.resources.getString(
- repository.primaryAuthMessage.value!!.message!!.messageResId!!
- )
- )
- .isEqualTo("Wrong PIN. Try again.")
+ assertThat(bouncerMessage).isNotNull()
+ assertThat(primaryResMessage(bouncerMessage)).isEqualTo("Wrong PIN. Try again.")
}
@Test
fun onUserStartsPrimaryAuthInput_clearsAllSetBouncerMessages() =
testScope.runTest {
init()
- repository.setCustomMessage(message("not empty"))
- repository.setFaceAcquisitionMessage(message("not empty"))
- repository.setFingerprintAcquisitionMessage(message("not empty"))
- repository.setPrimaryAuthMessage(message("not empty"))
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
+ underTest.onPrimaryAuthIncorrectAttempt()
+ assertThat(primaryResMessage(bouncerMessage)).isEqualTo("Wrong PIN. Try again.")
underTest.onPrimaryBouncerUserInput()
- assertThat(repository.customMessage.value).isNull()
- assertThat(repository.faceAcquisitionMessage.value).isNull()
- assertThat(repository.fingerprintAcquisitionMessage.value).isNull()
- assertThat(repository.primaryAuthMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
}
@Test
- fun onBouncerBeingHidden_clearsAllSetBouncerMessages() =
+ fun setCustomMessage_propagateValue() =
testScope.runTest {
init()
- repository.setCustomMessage(message("not empty"))
- repository.setFaceAcquisitionMessage(message("not empty"))
- repository.setFingerprintAcquisitionMessage(message("not empty"))
- repository.setPrimaryAuthMessage(message("not empty"))
-
- underTest.onBouncerBeingHidden()
-
- assertThat(repository.customMessage.value).isNull()
- assertThat(repository.faceAcquisitionMessage.value).isNull()
- assertThat(repository.fingerprintAcquisitionMessage.value).isNull()
- assertThat(repository.primaryAuthMessage.value).isNull()
- }
-
- @Test
- fun setCustomMessage_setsRepositoryValue() =
- testScope.runTest {
- init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.setCustomMessage("not empty")
- val customMessage = repository.customMessage
- assertThat(customMessage.value!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
- assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty")
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isEqualTo("not empty")
underTest.setCustomMessage(null)
- assertThat(customMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
- fun setFaceMessage_setsRepositoryValue() =
+ fun setFaceMessage_propagateValue() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.setFaceAcquisitionMessage("not empty")
- val faceAcquisitionMessage = repository.faceAcquisitionMessage
-
- assertThat(faceAcquisitionMessage.value!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
- assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message)
- .isEqualTo("not empty")
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isEqualTo("not empty")
underTest.setFaceAcquisitionMessage(null)
- assertThat(faceAcquisitionMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
- fun setFingerprintMessage_setsRepositoryValue() =
+ fun setFingerprintMessage_propagateValue() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.setFingerprintAcquisitionMessage("not empty")
- val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage
-
- assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
- assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message)
- .isEqualTo("not empty")
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isEqualTo("not empty")
underTest.setFingerprintAcquisitionMessage(null)
- assertThat(fingerprintAcquisitionMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
fun onPrimaryAuthLockout_startsTimerForSpecifiedNumberOfSeconds() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.onPrimaryAuthLockedOut(3)
@@ -206,7 +235,7 @@
countDownTimerCallback.value.onTick(2000L)
- val primaryMessage = repository.primaryAuthMessage.value!!.message!!
+ val primaryMessage = bouncerMessage!!.message!!
assertThat(primaryMessage.messageResId!!)
.isEqualTo(kg_too_many_failed_attempts_countdown)
assertThat(primaryMessage.formatterArgs).isEqualTo(mapOf(Pair("count", 2)))
@@ -216,10 +245,7 @@
fun onPrimaryAuthLockout_timerComplete_resetsRepositoryMessages() =
testScope.runTest {
init()
- repository.setCustomMessage(message("not empty"))
- repository.setFaceAcquisitionMessage(message("not empty"))
- repository.setFingerprintAcquisitionMessage(message("not empty"))
- repository.setPrimaryAuthMessage(message("not empty"))
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.onPrimaryAuthLockedOut(3)
@@ -228,59 +254,269 @@
countDownTimerCallback.value.onFinish()
- assertThat(repository.customMessage.value).isNull()
- assertThat(repository.faceAcquisitionMessage.value).isNull()
- assertThat(repository.fingerprintAcquisitionMessage.value).isNull()
- assertThat(repository.primaryAuthMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
- fun bouncerMessage_hasPriorityOrderOfMessages() =
+ fun onFaceLockout_propagatesState() =
testScope.runTest {
init()
- repository.setBiometricAuthMessage(message("biometric message"))
- repository.setFaceAcquisitionMessage(message("face acquisition message"))
- repository.setFingerprintAcquisitionMessage(message("fingerprint acquisition message"))
- repository.setPrimaryAuthMessage(message("primary auth message"))
- repository.setAuthFlagsMessage(message("auth flags message"))
- repository.setBiometricLockedOutMessage(message("biometrics locked out"))
- repository.setCustomMessage(message("custom message"))
+ val lockoutMessage by collectLastValue(underTest.bouncerMessage)
- assertThat(bouncerMessage()).isEqualTo(message("primary auth message"))
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ runCurrent()
- repository.setPrimaryAuthMessage(null)
+ assertThat(primaryResMessage(lockoutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(secondaryResMessage(lockoutMessage))
+ .isEqualTo("Can’t unlock with face. Too many attempts.")
- assertThat(bouncerMessage()).isEqualTo(message("biometric message"))
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ runCurrent()
- repository.setBiometricAuthMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("fingerprint acquisition message"))
-
- repository.setFingerprintAcquisitionMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("face acquisition message"))
-
- repository.setFaceAcquisitionMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("custom message"))
-
- repository.setCustomMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("auth flags message"))
-
- repository.setAuthFlagsMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("biometrics locked out"))
-
- repository.setBiometricLockedOutMessage(null)
-
- // sets the default message if everything else is null
- assertThat(bouncerMessage()!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
+ assertThat(primaryResMessage(lockoutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(lockoutMessage?.secondaryMessage?.message).isNull()
}
- private fun message(value: String): BouncerMessageModel {
- return BouncerMessageModel(message = Message(message = value))
+ @Test
+ fun onFaceLockout_whenItIsClass3_propagatesState() =
+ testScope.runTest {
+ init()
+ val lockoutMessage by collectLastValue(underTest.bouncerMessage)
+ fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockoutMessage)).isEqualTo("Enter PIN")
+ assertThat(secondaryResMessage(lockoutMessage))
+ .isEqualTo("PIN is required after too many attempts")
+
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockoutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(lockoutMessage?.secondaryMessage?.message).isNull()
+ }
+
+ @Test
+ fun onFingerprintLockout_propagatesState() =
+ testScope.runTest {
+ init()
+ val lockedOutMessage by collectLastValue(underTest.bouncerMessage)
+
+ fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockedOutMessage)).isEqualTo("Enter PIN")
+ assertThat(secondaryResMessage(lockedOutMessage))
+ .isEqualTo("PIN is required after too many attempts")
+
+ fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockedOutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(lockedOutMessage?.secondaryMessage?.message).isNull()
+ }
+
+ @Test
+ fun onRestartForMainlineUpdate_shouldProvideRelevantMessage() =
+ testScope.runTest {
+ init()
+ whenever(systemPropertiesHelper.get("sys.boot.reason.last"))
+ .thenReturn("reboot,mainline_update")
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "Device updated. Enter PIN to continue.")
+ )
+ }
+
+ @Test
+ fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() =
+ testScope.runTest {
+ init()
+ fakeTrustRepository.setTrustUsuallyManaged(false)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+ val defaultMessage = Pair("Enter PIN", null)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy")
+ )
+ }
+
+ @Test
+ fun authFlagsChanges_withTrustManaged_providesDifferentMessages() =
+ testScope.runTest {
+ init()
+
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+ fakeTrustRepository.setCurrentUserTrustManaged(true)
+ fakeTrustRepository.setTrustUsuallyManaged(true)
+
+ val defaultMessage = Pair("Enter PIN", null)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ Pair("Enter PIN", "Trust agent is unavailable"),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ Pair("Enter PIN", "Trust agent is unavailable"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "Update will install when device not in use"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Enter PIN",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ @Test
+ fun authFlagsChanges_withFaceEnrolled_providesDifferentMessages() =
+ testScope.runTest {
+ init()
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ fakeTrustRepository.setTrustUsuallyManaged(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+ val defaultMessage = Pair("Enter PIN", null)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "Update will install when device not in use"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Enter PIN",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ @Test
+ fun authFlagsChanges_withFingerprintEnrolled_providesDifferentMessages() =
+ testScope.runTest {
+ init()
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ fakeTrustRepository.setCurrentUserTrustManaged(false)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to
+ Pair("Unlock with PIN or fingerprint", null)
+ )
+
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ Pair("Enter PIN", null),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ Pair("Enter PIN", null),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "Update will install when device not in use"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Enter PIN",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ private fun primaryResMessage(bouncerMessage: BouncerMessageModel?) =
+ resString(bouncerMessage?.message?.messageResId)
+
+ private fun secondaryResMessage(bouncerMessage: BouncerMessageModel?) =
+ resString(bouncerMessage?.secondaryMessage?.messageResId)
+
+ private fun resString(msgResId: Int?): String? =
+ msgResId?.let { context.resources.getString(it) }
+
+ private fun TestScope.verifyMessagesForAuthFlag(
+ vararg authFlagToExpectedMessages: Pair<Int, Pair<String, String?>>
+ ) {
+ val authFlagsMessage by collectLastValue(underTest.bouncerMessage)
+
+ authFlagToExpectedMessages.forEach { (flag, messagePair) ->
+ biometricSettingsRepository.setAuthenticationFlags(
+ AuthenticationFlags(PRIMARY_USER_ID, flag)
+ )
+ runCurrent()
+
+ assertThat(primaryResMessage(authFlagsMessage)).isEqualTo(messagePair.first)
+ if (messagePair.second == null) {
+ assertThat(authFlagsMessage?.secondaryMessage?.messageResId).isEqualTo(0)
+ assertThat(authFlagsMessage?.secondaryMessage?.message).isNull()
+ } else {
+ assertThat(authFlagsMessage?.secondaryMessage?.messageResId).isNotEqualTo(0)
+ assertThat(secondaryResMessage(authFlagsMessage)).isEqualTo(messagePair.second)
+ }
+ }
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
index 29d7500..7f784d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -260,4 +261,19 @@
listener.value.onIsActiveUnlockRunningChanged(true, users[0].id)
assertThat(isCurrentUserActiveUnlockRunning).isTrue()
}
+
+ @Test
+ fun isTrustUsuallyManaged_providesTheValueForCurrentUser() =
+ testScope.runTest {
+ runCurrent()
+ val trustUsuallyManaged by collectLastValue(underTest.isCurrentUserTrustUsuallyManaged)
+ whenever(trustManager.isTrustUsuallyManaged(users[0].id)).thenReturn(true)
+ whenever(trustManager.isTrustUsuallyManaged(users[1].id)).thenReturn(false)
+
+ userRepository.setSelectedUserInfo(users[0])
+
+ assertThat(trustUsuallyManaged).isTrue()
+ userRepository.setSelectedUserInfo(users[1])
+ assertThat(trustUsuallyManaged).isFalse()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 223b1c4..9651072 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade
+import android.os.Handler
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.KeyEvent
@@ -24,29 +25,42 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardMessageAreaController
import com.android.keyguard.KeyguardSecurityContainerController
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.back.domain.interactor.BackActionInteractor
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
+import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+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.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.log.BouncerLogger
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -62,6 +76,7 @@
import com.android.systemui.statusbar.phone.DozeServiceHost
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -201,11 +216,35 @@
featureFlags,
fakeClock,
BouncerMessageInteractor(
- FakeBouncerMessageRepository(),
- mock(BouncerMessageFactory::class.java),
- FakeUserRepository(),
- CountDownTimerUtil(),
- featureFlags
+ repository = BouncerMessageRepositoryImpl(),
+ userRepository = FakeUserRepository(),
+ countDownTimerUtil = mock(CountDownTimerUtil::class.java),
+ featureFlags = featureFlags,
+ updateMonitor = mock(KeyguardUpdateMonitor::class.java),
+ biometricSettingsRepository = FakeBiometricSettingsRepository(),
+ applicationScope = testScope.backgroundScope,
+ trustRepository = FakeTrustRepository(),
+ systemPropertiesHelper = mock(SystemPropertiesHelper::class.java),
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ FakeKeyguardBouncerRepository(),
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ context,
+ mock(KeyguardUpdateMonitor::class.java),
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ ),
+ facePropertyRepository = FakeFacePropertyRepository(),
+ deviceEntryFingerprintAuthRepository =
+ FakeDeviceEntryFingerprintAuthRepository(),
+ faceAuthRepository = FakeDeviceEntryFaceAuthRepository(),
+ securityModel = mock(KeyguardSecurityModel::class.java),
),
BouncerLogger(logcatLogBuffer("BouncerLog")),
keyEventInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index e817016..0023020 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.shade
+import android.os.Handler
import android.os.SystemClock
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
@@ -23,28 +24,41 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardMessageAreaController
import com.android.keyguard.KeyguardSecurityContainerController
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.back.domain.interactor.BackActionInteractor
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
+import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+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.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.log.BouncerLogger
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -60,6 +74,7 @@
import com.android.systemui.statusbar.phone.DozeScrimController
import com.android.systemui.statusbar.phone.DozeServiceHost
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -203,11 +218,35 @@
featureFlags,
FakeSystemClock(),
BouncerMessageInteractor(
- FakeBouncerMessageRepository(),
- Mockito.mock(BouncerMessageFactory::class.java),
- FakeUserRepository(),
- CountDownTimerUtil(),
- featureFlags
+ repository = BouncerMessageRepositoryImpl(),
+ userRepository = FakeUserRepository(),
+ countDownTimerUtil = Mockito.mock(CountDownTimerUtil::class.java),
+ featureFlags = featureFlags,
+ updateMonitor = Mockito.mock(KeyguardUpdateMonitor::class.java),
+ biometricSettingsRepository = FakeBiometricSettingsRepository(),
+ applicationScope = testScope.backgroundScope,
+ trustRepository = FakeTrustRepository(),
+ systemPropertiesHelper = Mockito.mock(SystemPropertiesHelper::class.java),
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ FakeKeyguardBouncerRepository(),
+ Mockito.mock(BouncerView::class.java),
+ Mockito.mock(Handler::class.java),
+ Mockito.mock(KeyguardStateController::class.java),
+ Mockito.mock(KeyguardSecurityModel::class.java),
+ Mockito.mock(PrimaryBouncerCallbackInteractor::class.java),
+ Mockito.mock(FalsingCollector::class.java),
+ Mockito.mock(DismissCallbackRegistry::class.java),
+ context,
+ Mockito.mock(KeyguardUpdateMonitor::class.java),
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ ),
+ facePropertyRepository = FakeFacePropertyRepository(),
+ deviceEntryFingerprintAuthRepository =
+ FakeDeviceEntryFingerprintAuthRepository(),
+ faceAuthRepository = FakeDeviceEntryFaceAuthRepository(),
+ securityModel = Mockito.mock(KeyguardSecurityModel::class.java),
),
BouncerLogger(logcatLogBuffer("BouncerLog")),
Mockito.mock(KeyEventInteractor::class.java),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt
deleted file mode 100644
index d9b926d..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.bouncer.data.repository
-
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-
-class FakeBouncerMessageRepository : BouncerMessageRepository {
- private val _primaryAuthMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val primaryAuthMessage: StateFlow<BouncerMessageModel?>
- get() = _primaryAuthMessage
-
- private val _faceAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val faceAcquisitionMessage: StateFlow<BouncerMessageModel?>
- get() = _faceAcquisitionMessage
- private val _fingerprintAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val fingerprintAcquisitionMessage: StateFlow<BouncerMessageModel?>
- get() = _fingerprintAcquisitionMessage
- private val _customMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val customMessage: StateFlow<BouncerMessageModel?>
- get() = _customMessage
- private val _biometricAuthMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val biometricAuthMessage: StateFlow<BouncerMessageModel?>
- get() = _biometricAuthMessage
- private val _authFlagsMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val authFlagsMessage: StateFlow<BouncerMessageModel?>
- get() = _authFlagsMessage
-
- private val _biometricLockedOutMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val biometricLockedOutMessage: Flow<BouncerMessageModel?>
- get() = _biometricLockedOutMessage
-
- override fun setPrimaryAuthMessage(value: BouncerMessageModel?) {
- _primaryAuthMessage.value = value
- }
-
- override fun setFaceAcquisitionMessage(value: BouncerMessageModel?) {
- _faceAcquisitionMessage.value = value
- }
-
- override fun setFingerprintAcquisitionMessage(value: BouncerMessageModel?) {
- _fingerprintAcquisitionMessage.value = value
- }
-
- override fun setCustomMessage(value: BouncerMessageModel?) {
- _customMessage.value = value
- }
-
- fun setBiometricAuthMessage(value: BouncerMessageModel?) {
- _biometricAuthMessage.value = value
- }
-
- fun setAuthFlagsMessage(value: BouncerMessageModel?) {
- _authFlagsMessage.value = value
- }
-
- fun setBiometricLockedOutMessage(value: BouncerMessageModel?) {
- _biometricLockedOutMessage.value = value
- }
-
- override fun clearMessage() {
- _primaryAuthMessage.value = null
- _faceAcquisitionMessage.value = null
- _fingerprintAcquisitionMessage.value = null
- _customMessage.value = null
- }
-}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
index 9d98f94..482126d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
@@ -25,6 +25,9 @@
import kotlinx.coroutines.flow.asStateFlow
class FakeTrustRepository : TrustRepository {
+ private val _isTrustUsuallyManaged = MutableStateFlow(false)
+ override val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean>
+ get() = _isTrustUsuallyManaged
private val _isCurrentUserTrusted = MutableStateFlow(false)
override val isCurrentUserTrusted: Flow<Boolean>
get() = _isCurrentUserTrusted
@@ -55,4 +58,8 @@
fun setRequestDismissKeyguard(trustModel: TrustModel) {
_requestDismissKeyguard.value = trustModel
}
+
+ fun setTrustUsuallyManaged(value: Boolean) {
+ _isTrustUsuallyManaged.value = value
+ }
}