From d8555b693ace6a6cdf3110334a8ed30f9bae49c6 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Tue, 1 Aug 2023 17:36:09 -0700 Subject: [PATCH 1/8] Do not show the primary auth lockout dialog if the feature flag is enabled Test: verified manually Fixes: 293476896 Change-Id: I986c52b8e46f0d912c4511c9eb70a3fa5fe2ebdf --- .../keyguard/KeyguardSecurityContainerController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 3b09910fbe88a..aff25914ec363 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -27,6 +27,7 @@ import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY; import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER; import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE; import static com.android.systemui.DejankUtils.whitelistIpcs; +import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES; import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; @@ -1081,8 +1082,10 @@ public class KeyguardSecurityContainerController extends ViewController 0) { mLockPatternUtils.reportPasswordLockout(timeoutMs, userId); - mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils, - mSecurityModel.getSecurityMode(userId)); + if (!mFeatureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) { + mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils, + mSecurityModel.getSecurityMode(userId)); + } } } From 41c58ce8ec7cf4d3ed460c198430c347fb9a68a1 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Tue, 1 Aug 2023 17:35:21 -0700 Subject: [PATCH 2/8] Fixes issue with wrong pin input message not being shown This chain of calls lead us to reset the primary auth error message because we assume that the user has started entering their primary auth again. KeyguardPinBasedInputView#resetPasswordText -> PasswordTextView#reset -> PasswordTextView#userActivity() -> UserActivityListener#onUserActivity -> KeyguardAbsKeyInputViewController#onUserInput -> KeyguardSecurityCallback#onUserInput -> BouncerMessageInteractor#onPrimaryBouncerUserInput() This fix invokes the resetPasswordText before we invoke `reportUnlockAttempt` so that the primary auth error message doesn't get cleared out Fixes: 293475939 Test: verified manually Change-Id: Ie7c144bf96cc542d9aae11c255394bd9ca10f2a0 --- .../com/android/keyguard/KeyguardAbsKeyInputViewController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index bb112175ded7b..b81e08183cdc4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -178,6 +178,7 @@ public abstract class KeyguardAbsKeyInputViewController 0) { @@ -186,7 +187,6 @@ public abstract class KeyguardAbsKeyInputViewController Date: Mon, 31 Jul 2023 15:44:55 -0700 Subject: [PATCH 3/8] Update message shown for unattended update Fixes: 293477849 Test: verified manually, 1. Enable the feature flag 2. Unlock the device 3. Run `adb shell cmd recovery request-lskf ota` 4. Suspend the device and go to the bouncer 5. New message should be shown Change-Id: I1fe0718de43769424dd7eeff65faec935caea89d --- packages/SystemUI/res-keyguard/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index badad584824b8..28b58703b02de 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -192,7 +192,7 @@ Pattern is required after lockdown - Update will install during inactive hours + Update will install when device not in use Added security required. PIN not used for a while. From e4726ac63ac2f184191dd231d5f8dd7f8b3f08d7 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Thu, 27 Jul 2023 03:02:01 -0700 Subject: [PATCH 4/8] Show unlock with fingerprint message for co-ex face locked out scenario Bug: 236891644 Test: verified manually Change-Id: I59e48540214b6c2a1ff3b43acf5b5213e163e18e --- .../bouncer/data/factory/BouncerMessageFactory.kt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) 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 index 3206c0043d5c3..3b0b8125c02b9 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt @@ -131,7 +131,9 @@ constructor( PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode) PROMPT_REASON_PREPARE_FOR_UPDATE -> authRequiredForUnattendedUpdate(securityMode) PROMPT_REASON_FINGERPRINT_LOCKED_OUT -> fingerprintUnlockUnavailable(securityMode) - PROMPT_REASON_FACE_LOCKED_OUT -> faceUnlockUnavailable(securityMode) + PROMPT_REASON_FACE_LOCKED_OUT -> + if (fpAllowedInBouncer) faceLockedOutButFingerprintAvailable(securityMode) + else faceLockedOut(securityMode) PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT -> if (fpAllowedInBouncer) incorrectSecurityInputWithFingerprint(securityMode) else incorrectSecurityInput(securityMode) @@ -311,7 +313,7 @@ private fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMod } } -private fun faceUnlockUnavailable(securityMode: SecurityMode): Pair { +private fun faceLockedOut(securityMode: SecurityMode): Pair { return when (securityMode) { SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out) SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out) @@ -320,6 +322,15 @@ private fun faceUnlockUnavailable(securityMode: SecurityMode): Pair { } } +private fun faceLockedOutButFingerprintAvailable(securityMode: SecurityMode): Pair { + 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 { return when (securityMode) { SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_fp_locked_out) From 0bbf640c18a1316e7921869cb9e87d2df3e1b745 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Wed, 2 Aug 2023 11:45:17 -0700 Subject: [PATCH 5/8] Remove code that was added to disable the views for udc-dev `udc-dev` didn't have the CL that hid the message views when the feature flag is disabled. This change is not needed in udc-qpr-dev Bug: 236891644 Test: verified manually 1. enable feature flag, see new messages 2. disable feature flag, see old messages 3. Enable layout bounds in developer options, and see that the views are not in the layout when feature flag is disabled Change-Id: I9ce0fe29284cbeea8dbad13f74c27af987facf59 --- .../src/com/android/systemui/bouncer/ui/BouncerMessageView.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt index 47fac2b4269dd..648680293e3d8 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt @@ -41,8 +41,6 @@ class BouncerMessageView : LinearLayout { super.onFinishInflate() primaryMessageView = findViewById(R.id.bouncer_primary_message_area) secondaryMessageView = findViewById(R.id.bouncer_secondary_message_area) - primaryMessageView?.disable() - secondaryMessageView?.disable() } fun init(factory: KeyguardMessageAreaController.Factory) { From 42f70e51c35f57afdebd760dbf3eecda528b5585 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Mon, 31 Jul 2023 16:17:27 -0700 Subject: [PATCH 6/8] Support custom messages for mainline update Fixes: 293476665 Test: atest BouncerMessageRepositoryTest Test: verified manually, 1. Enable feature flag 2. Reboot the device 3. Before unlocking, run the command: `adb shell setprop sys.boot.reason.last reboot,mainline_update` 4. Relevant message should be shown on bouncer. Change-Id: I3f7029f586013159eff0756798f81048de372098 --- .../data/factory/BouncerMessageFactory.kt | 15 ++++++++++++++ .../repository/BouncerMessageRepository.kt | 12 ++++++++++- .../data/repo/BouncerMessageRepositoryTest.kt | 20 ++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) 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 index 3b0b8125c02b9..4f6023b54fa95 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt @@ -32,6 +32,7 @@ import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMET 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 @@ -53,6 +54,9 @@ import com.android.systemui.R.string.kg_primary_auth_locked_out_password import com.android.systemui.R.string.kg_primary_auth_locked_out_pattern import com.android.systemui.R.string.kg_primary_auth_locked_out_pin import com.android.systemui.R.string.kg_prompt_after_dpm_lock +import com.android.systemui.R.string.kg_prompt_after_update_password +import com.android.systemui.R.string.kg_prompt_after_update_pattern +import com.android.systemui.R.string.kg_prompt_after_update_pin import com.android.systemui.R.string.kg_prompt_after_user_lockdown_password import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pattern import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pin @@ -130,6 +134,7 @@ constructor( PROMPT_REASON_USER_REQUEST -> authRequiredAfterUserLockdown(securityMode) PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(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_FACE_LOCKED_OUT -> if (fpAllowedInBouncer) faceLockedOutButFingerprintAvailable(securityMode) @@ -174,6 +179,7 @@ constructor( PROMPT_REASON_NONE, PROMPT_REASON_RESTART, PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT, + PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE, ) annotation class BouncerPromptReason @@ -286,6 +292,15 @@ private fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): Pair { + 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 { return when (securityMode) { SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout) 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 7e420cfcea757..6fb0d4cc5e135 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 @@ -28,6 +28,7 @@ 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 @@ -38,6 +39,7 @@ 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 @@ -105,6 +107,9 @@ interface BouncerMessageRepository { fun clearMessage() } +private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last" +private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update" + @SysUISingleton class BouncerMessageRepositoryImpl @Inject @@ -114,6 +119,7 @@ constructor( updateMonitor: KeyguardUpdateMonitor, private val bouncerMessageFactory: BouncerMessageFactory, private val userRepository: UserRepository, + private val systemPropertiesHelper: SystemPropertiesHelper, fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, ) : BouncerMessageRepository { @@ -132,6 +138,9 @@ constructor( private val isAnyBiometricsEnabledAndEnrolled = or(isFaceEnrolledAndEnabled, isFingerprintEnrolledAndEnabled) + private val wasRebootedForMainlineUpdate + get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE + private val authFlagsBasedPromptReason: Flow = combine( biometricSettingsRepository.authenticationFlags, @@ -144,7 +153,8 @@ constructor( return@map if ( trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot ) { - PROMPT_REASON_RESTART + if (wasRebootedForMainlineUpdate) PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE + else PROMPT_REASON_RESTART } else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) { PROMPT_REASON_TIMEOUT } else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) { 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 index de712da9d99bf..ade09b916df40 100644 --- 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 @@ -51,6 +51,7 @@ 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 @@ -79,6 +80,7 @@ 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 @@ -108,7 +110,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { updateMonitor = updateMonitor, bouncerMessageFactory = BouncerMessageFactory(updateMonitor, securityModel), userRepository = userRepository, - fingerprintAuthRepository = fingerprintRepository + fingerprintAuthRepository = fingerprintRepository, + systemPropertiesHelper = systemPropertiesHelper ) } @@ -213,6 +216,21 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { 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.setFaceEnrolled(true) + biometricSettingsRepository.setIsFaceAuthEnabled(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 { From 9b08fcb5e9b0b5ab6d9e817448566add5cb8c232 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Tue, 1 Aug 2023 17:25:06 -0700 Subject: [PATCH 7/8] Use the default message as the primary line for fp/face acquisition messages Also, stop animating the messages to avoid the flicker for fp/face acquisition messages/primary auth lockout messages. Fixes: 293476712 Test: verified manually Test: atest BouncerMessageFactoryTest Test: atest BouncerMessageInteractorTest Change-Id: I5539cdaf843de9a1d4a67797a2eb70eed9b6e0d2 --- .../data/factory/BouncerMessageFactory.kt | 21 +++++++-------- .../interactor/BouncerMessageInteractor.kt | 21 +++++++++++---- .../data/factory/BouncerMessageFactoryTest.kt | 25 +++++++++++++++-- .../data/repo/BouncerMessageRepositoryTest.kt | 4 +-- .../BouncerMessageInteractorTest.kt | 27 ++++++++++++------- 5 files changed, 69 insertions(+), 29 deletions(-) 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 index 4f6023b54fa95..d767c47caeac2 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt @@ -93,6 +93,7 @@ constructor( fun createFromPromptReason( @BouncerPromptReason reason: Int, userId: Int, + secondaryMsgOverride: String? = null ): BouncerMessageModel? { val pair = getBouncerMessage( @@ -102,21 +103,16 @@ constructor( ) return pair?.let { BouncerMessageModel( - message = Message(messageResId = pair.first), - secondaryMessage = Message(messageResId = pair.second) + message = Message(messageResId = pair.first, animate = false), + secondaryMessage = + secondaryMsgOverride?.let { + Message(message = secondaryMsgOverride, animate = false) + } + ?: Message(messageResId = pair.second, animate = false) ) } } - fun createFromString( - primaryMsg: String? = null, - secondaryMsg: String? = null - ): BouncerMessageModel = - BouncerMessageModel( - message = primaryMsg?.let { Message(message = it) }, - secondaryMessage = secondaryMsg?.let { Message(message = it) }, - ) - /** * Helper method that provides the relevant bouncer message that should be shown for different * scenarios indicated by [reason]. [securityMode] & [fpAllowedInBouncer] parameters are used to @@ -159,6 +155,9 @@ constructor( else -> null } } + + fun emptyMessage(): BouncerMessageModel = + BouncerMessageModel(Message(message = ""), Message(message = "")) } @Retention(AnnotationRetention.SOURCE) 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 d06dd8e1c1241..fe01d081e60ca 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 @@ -86,7 +86,11 @@ constructor( repository.setFingerprintAcquisitionMessage( if (value != null) { - factory.createFromString(secondaryMsg = value) + factory.createFromPromptReason( + PROMPT_REASON_DEFAULT, + userRepository.getSelectedUserInfo().id, + secondaryMsgOverride = value + ) } else { null } @@ -98,7 +102,11 @@ constructor( repository.setFaceAcquisitionMessage( if (value != null) { - factory.createFromString(secondaryMsg = value) + factory.createFromPromptReason( + PROMPT_REASON_DEFAULT, + userRepository.getSelectedUserInfo().id, + secondaryMsgOverride = value + ) } else { null } @@ -110,7 +118,11 @@ constructor( repository.setCustomMessage( if (value != null) { - factory.createFromString(secondaryMsg = value) + factory.createFromPromptReason( + PROMPT_REASON_DEFAULT, + userRepository.getSelectedUserInfo().id, + secondaryMsgOverride = value + ) } else { null } @@ -140,8 +152,7 @@ constructor( // always maps to an empty string. private fun nullOrEmptyMessage() = flowOf( - if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null - else factory.createFromString("", "") + if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null else factory.emptyMessage() ) val bouncerMessage = 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 index 992ee1a83254b..77dd9eeb261cc 100644 --- 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 @@ -77,6 +77,22 @@ class BouncerMessageFactoryTest : SysuiTestCase() { .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_basedOnSecurityModeAndFpAllowedInBouncer() = testScope.runTest { @@ -149,11 +165,16 @@ class BouncerMessageFactoryTest : SysuiTestCase() { private fun bouncerMessageModel( mode: KeyguardSecurityModel.SecurityMode, fpAllowedInBouncer: Boolean, - reason: Int + reason: Int, + secondaryMessageOverride: String? = null, ): BouncerMessageModel? { whenever(securityModel.getSecurityMode(0)).thenReturn(mode) whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(fpAllowedInBouncer) - return underTest.createFromPromptReason(reason, 0) + 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 index ade09b916df40..e1b608b6f544a 100644 --- 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 @@ -363,8 +363,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { private fun message(primaryResId: Int, secondaryResId: Int): BouncerMessageModel { return BouncerMessageModel( - message = Message(messageResId = primaryResId), - secondaryMessage = Message(messageResId = secondaryResId) + message = Message(messageResId = primaryResId, animate = false), + secondaryMessage = Message(messageResId = secondaryResId, animate = false) ) } private fun message(value: String): BouncerMessageModel { 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 8e5256e970a30..283c02f925e45 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 @@ -150,11 +150,12 @@ class BouncerMessageInteractorTest : SysuiTestCase() { underTest.setCustomMessage("not empty") - assertThat(repository.customMessage.value) - .isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty"))) + val customMessage = repository.customMessage + assertThat(customMessage.value!!.message!!.messageResId).isEqualTo(keyguard_enter_pin) + assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty") underTest.setCustomMessage(null) - assertThat(repository.customMessage.value).isNull() + assertThat(customMessage.value).isNull() } @Test @@ -164,11 +165,15 @@ class BouncerMessageInteractorTest : SysuiTestCase() { underTest.setFaceAcquisitionMessage("not empty") - assertThat(repository.faceAcquisitionMessage.value) - .isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty"))) + val faceAcquisitionMessage = repository.faceAcquisitionMessage + + assertThat(faceAcquisitionMessage.value!!.message!!.messageResId) + .isEqualTo(keyguard_enter_pin) + assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message) + .isEqualTo("not empty") underTest.setFaceAcquisitionMessage(null) - assertThat(repository.faceAcquisitionMessage.value).isNull() + assertThat(faceAcquisitionMessage.value).isNull() } @Test @@ -178,11 +183,15 @@ class BouncerMessageInteractorTest : SysuiTestCase() { underTest.setFingerprintAcquisitionMessage("not empty") - assertThat(repository.fingerprintAcquisitionMessage.value) - .isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty"))) + val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage + + assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId) + .isEqualTo(keyguard_enter_pin) + assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message) + .isEqualTo("not empty") underTest.setFingerprintAcquisitionMessage(null) - assertThat(repository.fingerprintAcquisitionMessage.value).isNull() + assertThat(fingerprintAcquisitionMessage.value).isNull() } @Test From e23d096683b734c797fca006de3c294b56dfaf14 Mon Sep 17 00:00:00 2001 From: Chandru S Date: Tue, 1 Aug 2023 17:27:09 -0700 Subject: [PATCH 8/8] Change the default message to include fingerprint even for UDFPS. Previously, we want to show the FP specific message only if FP auth was allowed on bouncer (SFPS) UX requested that we can change this to be more generic, if FP auth is allowed at all we should show the FP specific message Fixes: 293616192 Test: verified manually Change-Id: Ibca81eedf9fe842903773aa213d73d4bd02f1d50 --- .../keyguard/KeyguardUpdateMonitor.java | 8 ---- .../data/factory/BouncerMessageFactory.kt | 31 ++++++++------ .../data/factory/BouncerMessageFactoryTest.kt | 42 +++++++++---------- .../data/repo/BouncerMessageRepositoryTest.kt | 2 +- .../BouncerMessageInteractorTest.kt | 2 +- 5 files changed, 40 insertions(+), 45 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 53229b9945a50..d950c917d8a37 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2695,14 +2695,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return mAuthController.isUdfpsSupported(); } - /** - * @return true if the FP sensor is non-UDFPS and the device can be unlocked using fingerprint - * at this moment. - */ - public boolean isFingerprintAllowedInBouncer() { - return !isUdfpsSupported() && isUnlockingWithFingerprintAllowed(); - } - /** * @return true if there's at least one sfps enrollment for the current user. */ 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 index d767c47caeac2..1817ea9024fce 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt @@ -99,7 +99,7 @@ constructor( getBouncerMessage( reason, securityModel.getSecurityMode(userId), - updateMonitor.isFingerprintAllowedInBouncer + updateMonitor.isUnlockingWithFingerprintAllowed ) return pair?.let { BouncerMessageModel( @@ -115,43 +115,48 @@ constructor( /** * Helper method that provides the relevant bouncer message that should be shown for different - * scenarios indicated by [reason]. [securityMode] & [fpAllowedInBouncer] parameters are used to + * scenarios indicated by [reason]. [securityMode] & [fpAuthIsAllowed] parameters are used to * provide a more specific message. */ private fun getBouncerMessage( @BouncerPromptReason reason: Int, securityMode: SecurityMode, - fpAllowedInBouncer: Boolean = false + fpAuthIsAllowed: Boolean = false ): Pair? { 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_AFTER_LOCKOUT -> biometricLockout(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 (fpAllowedInBouncer) faceLockedOutButFingerprintAvailable(securityMode) + if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode) else faceLockedOut(securityMode) - PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT -> - if (fpAllowedInBouncer) incorrectSecurityInputWithFingerprint(securityMode) - else incorrectSecurityInput(securityMode) PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT -> - if (fpAllowedInBouncer) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode) + if (fpAuthIsAllowed) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode) else nonStrongAuthTimeout(securityMode) PROMPT_REASON_TRUSTAGENT_EXPIRED -> - if (fpAllowedInBouncer) trustAgentDisabledWithFingerprintAllowed(securityMode) + 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 (fpAllowedInBouncer) incorrectFaceInputWithFingerprintAllowed(securityMode) + if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode) else incorrectFaceInput(securityMode) PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT -> incorrectFingerprintInput(securityMode) + // Default message PROMPT_REASON_DEFAULT -> - if (fpAllowedInBouncer) defaultMessageWithFingerprint(securityMode) + if (fpAuthIsAllowed) defaultMessageWithFingerprint(securityMode) else defaultMessage(securityMode) - PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT -> primaryAuthLockedOut(securityMode) else -> null } } 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 index 77dd9eeb261cc..efae3fe1af2c7 100644 --- 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 @@ -59,21 +59,21 @@ class BouncerMessageFactoryTest : SysuiTestCase() { } @Test - fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAllowedInBouncer() = + fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAuthIsAllowed() = testScope.runTest { - primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAllowedInBouncer = false) + primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = false) .isEqualTo("Enter PIN") - primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAllowedInBouncer = true) + primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = true) .isEqualTo("Unlock with PIN or fingerprint") - primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAllowedInBouncer = false) + primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = false) .isEqualTo("Enter password") - primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAllowedInBouncer = true) + primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = true) .isEqualTo("Unlock with password or fingerprint") - primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAllowedInBouncer = false) + primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = false) .isEqualTo("Draw pattern") - primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAllowedInBouncer = true) + primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = true) .isEqualTo("Unlock with pattern or fingerprint") } @@ -94,44 +94,44 @@ class BouncerMessageFactoryTest : SysuiTestCase() { } @Test - fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAllowedInBouncer() = + fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAuthIsAllowed() = testScope.runTest { primaryMessage( PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, mode = PIN, - fpAllowedInBouncer = true + fpAuthAllowed = true ) .isEqualTo("Wrong PIN. Try again.") secondaryMessage( PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, mode = PIN, - fpAllowedInBouncer = true + fpAuthAllowed = true ) .isEqualTo("Or unlock with fingerprint") primaryMessage( PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, mode = Password, - fpAllowedInBouncer = true + fpAuthAllowed = true ) .isEqualTo("Wrong password. Try again.") secondaryMessage( PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, mode = Password, - fpAllowedInBouncer = true + fpAuthAllowed = true ) .isEqualTo("Or unlock with fingerprint") primaryMessage( PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, mode = Pattern, - fpAllowedInBouncer = true + fpAuthAllowed = true ) .isEqualTo("Wrong pattern. Try again.") secondaryMessage( PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, mode = Pattern, - fpAllowedInBouncer = true + fpAuthAllowed = true ) .isEqualTo("Or unlock with fingerprint") } @@ -139,11 +139,11 @@ class BouncerMessageFactoryTest : SysuiTestCase() { private fun primaryMessage( reason: Int, mode: KeyguardSecurityModel.SecurityMode, - fpAllowedInBouncer: Boolean + fpAuthAllowed: Boolean ): StringSubject { return assertThat( context.resources.getString( - bouncerMessageModel(mode, fpAllowedInBouncer, reason)!!.message!!.messageResId!! + bouncerMessageModel(mode, fpAuthAllowed, reason)!!.message!!.messageResId!! ) )!! } @@ -151,25 +151,23 @@ class BouncerMessageFactoryTest : SysuiTestCase() { private fun secondaryMessage( reason: Int, mode: KeyguardSecurityModel.SecurityMode, - fpAllowedInBouncer: Boolean + fpAuthAllowed: Boolean ): StringSubject { return assertThat( context.resources.getString( - bouncerMessageModel(mode, fpAllowedInBouncer, reason)!! - .secondaryMessage!! - .messageResId!! + bouncerMessageModel(mode, fpAuthAllowed, reason)!!.secondaryMessage!!.messageResId!! ) )!! } private fun bouncerMessageModel( mode: KeyguardSecurityModel.SecurityMode, - fpAllowedInBouncer: Boolean, + fpAuthAllowed: Boolean, reason: Int, secondaryMessageOverride: String? = null, ): BouncerMessageModel? { whenever(securityModel.getSecurityMode(0)).thenReturn(mode) - whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(fpAllowedInBouncer) + whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(fpAuthAllowed) return underTest.createFromPromptReason( reason, 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 index e1b608b6f544a..2be7d8a43a189 100644 --- 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 @@ -101,7 +101,7 @@ class BouncerMessageRepositoryTest : SysuiTestCase() { fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository() testScope = TestScope() - whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(false) + whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false) whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN) underTest = BouncerMessageRepositoryImpl( 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 283c02f925e45..3ca94aa8e7afa 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 @@ -76,7 +76,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() { allowTestableLooperAsMainThread() whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN) - whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(false) + whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false) } suspend fun TestScope.init() {