Move all bouncer messages domain logic to the interactor

Summary of changes:
 1. Remove all duplicated state from the repository, we still need one field to save custom messages
 2. Migrate all the domain logic to the interactor
 3. Fix trust Agent disabled message not being shown, we need to check if trust is usually managed insted of currently managed.
 4. Check whether fingerprint auth is enrolled to show the "unlock with fingerprint" message
 5. Move the BouncerMessageRepository tests to the interactor
 6. If face auth is class3, then whenever face auth is locked out, we should show "Pin is required after too many attempts"
 7. Got rid of BouncerMessageFactory as well, having a separate prompt_reason and then mapping it in the factory seemed like an unnecessary step, now the interactor directly creates the model when it was returning the prompt reason.

Fixes: 293477650
Fixes: 293476775
Fixes: 293472698
Fixes: 293478276
Test: atest BouncerMessageInteractorTest
Test: atest TrustRepositoryTest

Change-Id: Ib33fa67c3238d3b219dc10ab26972202b3f7bbee
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..aecfe1d 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
+    }
 }