Merge changes Ibca81eed,I5539cdaf,I3f7029f5,I9ce0fe29,I59e48540, ... into udc-qpr-dev

* changes:
  Change the default message to include fingerprint even for UDFPS.
  Use the default message as the primary line for fp/face acquisition messages
  Support custom messages for mainline update
  Remove code that was added to disable the views for udc-dev
  Show unlock with fingerprint message for co-ex face locked out scenario
  Update message shown for unattended update
  Fixes issue with wrong pin input message not being shown
  Do not show the primary auth lockout dialog if the feature flag is enabled
This commit is contained in:
Chandru S
2023-08-03 16:29:56 +00:00
committed by Android (Google) Code Review
11 changed files with 173 additions and 83 deletions

View File

@@ -192,7 +192,7 @@
<string name="kg_prompt_after_user_lockdown_pattern">Pattern is required after lockdown</string> <string name="kg_prompt_after_user_lockdown_pattern">Pattern is required after lockdown</string>
<!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] --> <!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] -->
<string name="kg_prompt_unattended_update">Update will install during inactive hours</string> <string name="kg_prompt_unattended_update">Update will install when device not in use</string>
<!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=70] --> <!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=70] -->
<string name="kg_prompt_pin_auth_timeout">Added security required. PIN not used for a while.</string> <string name="kg_prompt_pin_auth_timeout">Added security required. PIN not used for a while.</string>

View File

@@ -178,6 +178,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode()); getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode());
} }
} else { } else {
mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
if (isValidPassword) { if (isValidPassword) {
getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs); getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
if (timeoutMs > 0) { if (timeoutMs > 0) {
@@ -186,7 +187,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
handleAttemptLockout(deadline); handleAttemptLockout(deadline);
} }
} }
mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
if (timeoutMs == 0) { if (timeoutMs == 0) {
mMessageAreaController.setMessage(mView.getWrongPasswordStringId()); mMessageAreaController.setMessage(mView.getWrongPasswordStringId());
} }

View File

@@ -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_SECONDARY_USER;
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE; import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
@@ -1081,10 +1082,12 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mLockPatternUtils.reportFailedPasswordAttempt(userId); mLockPatternUtils.reportFailedPasswordAttempt(userId);
if (timeoutMs > 0) { if (timeoutMs > 0) {
mLockPatternUtils.reportPasswordLockout(timeoutMs, userId); mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
if (!mFeatureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) {
mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils, mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
mSecurityModel.getSecurityMode(userId)); mSecurityModel.getSecurityMode(userId));
} }
} }
}
private void getCurrentSecurityController( private void getCurrentSecurityController(
KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback) { KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback) {

View File

@@ -2695,14 +2695,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return mAuthController.isUdfpsSupported(); 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. * @return true if there's at least one sfps enrollment for the current user.
*/ */

View File

@@ -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_PREPARE_FOR_UPDATE
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT 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
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_TIMEOUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST 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_pattern
import com.android.systemui.R.string.kg_primary_auth_locked_out_pin 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_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_password
import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pattern import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pattern
import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pin import com.android.systemui.R.string.kg_prompt_after_user_lockdown_pin
@@ -89,69 +93,76 @@ constructor(
fun createFromPromptReason( fun createFromPromptReason(
@BouncerPromptReason reason: Int, @BouncerPromptReason reason: Int,
userId: Int, userId: Int,
secondaryMsgOverride: String? = null
): BouncerMessageModel? { ): BouncerMessageModel? {
val pair = val pair =
getBouncerMessage( getBouncerMessage(
reason, reason,
securityModel.getSecurityMode(userId), securityModel.getSecurityMode(userId),
updateMonitor.isFingerprintAllowedInBouncer updateMonitor.isUnlockingWithFingerprintAllowed
) )
return pair?.let { return pair?.let {
BouncerMessageModel( BouncerMessageModel(
message = Message(messageResId = pair.first), message = Message(messageResId = pair.first, animate = false),
secondaryMessage = Message(messageResId = pair.second) 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 * 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. * provide a more specific message.
*/ */
private fun getBouncerMessage( private fun getBouncerMessage(
@BouncerPromptReason reason: Int, @BouncerPromptReason reason: Int,
securityMode: SecurityMode, securityMode: SecurityMode,
fpAllowedInBouncer: Boolean = false fpAuthIsAllowed: Boolean = false
): Pair<Int, Int>? { ): Pair<Int, Int>? {
return when (reason) { 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_RESTART -> authRequiredAfterReboot(securityMode)
PROMPT_REASON_TIMEOUT -> authRequiredAfterPrimaryAuthTimeout(securityMode) PROMPT_REASON_TIMEOUT -> authRequiredAfterPrimaryAuthTimeout(securityMode)
PROMPT_REASON_DEVICE_ADMIN -> authRequiredAfterAdminLockdown(securityMode) PROMPT_REASON_DEVICE_ADMIN -> authRequiredAfterAdminLockdown(securityMode)
PROMPT_REASON_USER_REQUEST -> authRequiredAfterUserLockdown(securityMode) PROMPT_REASON_USER_REQUEST -> authRequiredAfterUserLockdown(securityMode)
PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode)
PROMPT_REASON_PREPARE_FOR_UPDATE -> authRequiredForUnattendedUpdate(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_FINGERPRINT_LOCKED_OUT -> fingerprintUnlockUnavailable(securityMode)
PROMPT_REASON_FACE_LOCKED_OUT -> faceUnlockUnavailable(securityMode) PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode)
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT -> // Non strong auth not available reasons
if (fpAllowedInBouncer) incorrectSecurityInputWithFingerprint(securityMode) PROMPT_REASON_FACE_LOCKED_OUT ->
else incorrectSecurityInput(securityMode) if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode)
else faceLockedOut(securityMode)
PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT -> PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT ->
if (fpAllowedInBouncer) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode) if (fpAuthIsAllowed) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
else nonStrongAuthTimeout(securityMode) else nonStrongAuthTimeout(securityMode)
PROMPT_REASON_TRUSTAGENT_EXPIRED -> PROMPT_REASON_TRUSTAGENT_EXPIRED ->
if (fpAllowedInBouncer) trustAgentDisabledWithFingerprintAllowed(securityMode) if (fpAuthIsAllowed) trustAgentDisabledWithFingerprintAllowed(securityMode)
else trustAgentDisabled(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 -> PROMPT_REASON_INCORRECT_FACE_INPUT ->
if (fpAllowedInBouncer) incorrectFaceInputWithFingerprintAllowed(securityMode) if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode)
else incorrectFaceInput(securityMode) else incorrectFaceInput(securityMode)
PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT -> incorrectFingerprintInput(securityMode) PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT -> incorrectFingerprintInput(securityMode)
// Default message
PROMPT_REASON_DEFAULT -> PROMPT_REASON_DEFAULT ->
if (fpAllowedInBouncer) defaultMessageWithFingerprint(securityMode) if (fpAuthIsAllowed) defaultMessageWithFingerprint(securityMode)
else defaultMessage(securityMode) else defaultMessage(securityMode)
PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT -> primaryAuthLockedOut(securityMode)
else -> null else -> null
} }
} }
fun emptyMessage(): BouncerMessageModel =
BouncerMessageModel(Message(message = ""), Message(message = ""))
} }
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.SOURCE)
@@ -172,6 +183,7 @@ constructor(
PROMPT_REASON_NONE, PROMPT_REASON_NONE,
PROMPT_REASON_RESTART, PROMPT_REASON_RESTART,
PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT, PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT,
PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE,
) )
annotation class BouncerPromptReason annotation class BouncerPromptReason
@@ -284,6 +296,15 @@ private fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): Pair<In
} }
} }
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> { private fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): Pair<Int, Int> {
return when (securityMode) { return when (securityMode) {
SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout) SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
@@ -311,7 +332,7 @@ private fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMod
} }
} }
private fun faceUnlockUnavailable(securityMode: SecurityMode): Pair<Int, Int> { private fun faceLockedOut(securityMode: SecurityMode): Pair<Int, Int> {
return when (securityMode) { return when (securityMode) {
SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out) SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out) SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
@@ -320,6 +341,15 @@ private fun faceUnlockUnavailable(securityMode: SecurityMode): Pair<Int, Int> {
} }
} }
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> { private fun fingerprintUnlockUnavailable(securityMode: SecurityMode): Pair<Int, Int> {
return when (securityMode) { return when (securityMode) {
SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_fp_locked_out) SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_fp_locked_out)

View File

@@ -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_NON_STRONG_BIOMETRIC_TIMEOUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE 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
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_TIMEOUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST 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.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton 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.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.TrustRepository import com.android.systemui.keyguard.data.repository.TrustRepository
@@ -105,6 +107,9 @@ interface BouncerMessageRepository {
fun clearMessage() fun clearMessage()
} }
private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last"
private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"
@SysUISingleton @SysUISingleton
class BouncerMessageRepositoryImpl class BouncerMessageRepositoryImpl
@Inject @Inject
@@ -114,6 +119,7 @@ constructor(
updateMonitor: KeyguardUpdateMonitor, updateMonitor: KeyguardUpdateMonitor,
private val bouncerMessageFactory: BouncerMessageFactory, private val bouncerMessageFactory: BouncerMessageFactory,
private val userRepository: UserRepository, private val userRepository: UserRepository,
private val systemPropertiesHelper: SystemPropertiesHelper,
fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
) : BouncerMessageRepository { ) : BouncerMessageRepository {
@@ -132,6 +138,9 @@ constructor(
private val isAnyBiometricsEnabledAndEnrolled = private val isAnyBiometricsEnabledAndEnrolled =
or(isFaceEnrolledAndEnabled, isFingerprintEnrolledAndEnabled) or(isFaceEnrolledAndEnabled, isFingerprintEnrolledAndEnabled)
private val wasRebootedForMainlineUpdate
get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
private val authFlagsBasedPromptReason: Flow<Int> = private val authFlagsBasedPromptReason: Flow<Int> =
combine( combine(
biometricSettingsRepository.authenticationFlags, biometricSettingsRepository.authenticationFlags,
@@ -144,7 +153,8 @@ constructor(
return@map if ( return@map if (
trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot
) { ) {
PROMPT_REASON_RESTART if (wasRebootedForMainlineUpdate) PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
else PROMPT_REASON_RESTART
} else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) { } else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) {
PROMPT_REASON_TIMEOUT PROMPT_REASON_TIMEOUT
} else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) { } else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) {

View File

@@ -86,7 +86,11 @@ constructor(
repository.setFingerprintAcquisitionMessage( repository.setFingerprintAcquisitionMessage(
if (value != null) { if (value != null) {
factory.createFromString(secondaryMsg = value) factory.createFromPromptReason(
PROMPT_REASON_DEFAULT,
userRepository.getSelectedUserInfo().id,
secondaryMsgOverride = value
)
} else { } else {
null null
} }
@@ -98,7 +102,11 @@ constructor(
repository.setFaceAcquisitionMessage( repository.setFaceAcquisitionMessage(
if (value != null) { if (value != null) {
factory.createFromString(secondaryMsg = value) factory.createFromPromptReason(
PROMPT_REASON_DEFAULT,
userRepository.getSelectedUserInfo().id,
secondaryMsgOverride = value
)
} else { } else {
null null
} }
@@ -110,7 +118,11 @@ constructor(
repository.setCustomMessage( repository.setCustomMessage(
if (value != null) { if (value != null) {
factory.createFromString(secondaryMsg = value) factory.createFromPromptReason(
PROMPT_REASON_DEFAULT,
userRepository.getSelectedUserInfo().id,
secondaryMsgOverride = value
)
} else { } else {
null null
} }
@@ -140,8 +152,7 @@ constructor(
// always maps to an empty string. // always maps to an empty string.
private fun nullOrEmptyMessage() = private fun nullOrEmptyMessage() =
flowOf( flowOf(
if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null else factory.emptyMessage()
else factory.createFromString("", "")
) )
val bouncerMessage = val bouncerMessage =

View File

@@ -41,8 +41,6 @@ class BouncerMessageView : LinearLayout {
super.onFinishInflate() super.onFinishInflate()
primaryMessageView = findViewById(R.id.bouncer_primary_message_area) primaryMessageView = findViewById(R.id.bouncer_primary_message_area)
secondaryMessageView = findViewById(R.id.bouncer_secondary_message_area) secondaryMessageView = findViewById(R.id.bouncer_secondary_message_area)
primaryMessageView?.disable()
secondaryMessageView?.disable()
} }
fun init(factory: KeyguardMessageAreaController.Factory) { fun init(factory: KeyguardMessageAreaController.Factory) {

View File

@@ -59,63 +59,79 @@ class BouncerMessageFactoryTest : SysuiTestCase() {
} }
@Test @Test
fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAllowedInBouncer() = fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAuthIsAllowed() =
testScope.runTest { testScope.runTest {
primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAllowedInBouncer = false) primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = false)
.isEqualTo("Enter PIN") .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") .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") .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") .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") .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") .isEqualTo("Unlock with pattern or fingerprint")
} }
@Test @Test
fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAllowedInBouncer() = 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 { testScope.runTest {
primaryMessage( primaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = PIN, mode = PIN,
fpAllowedInBouncer = true fpAuthAllowed = true
) )
.isEqualTo("Wrong PIN. Try again.") .isEqualTo("Wrong PIN. Try again.")
secondaryMessage( secondaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = PIN, mode = PIN,
fpAllowedInBouncer = true fpAuthAllowed = true
) )
.isEqualTo("Or unlock with fingerprint") .isEqualTo("Or unlock with fingerprint")
primaryMessage( primaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Password, mode = Password,
fpAllowedInBouncer = true fpAuthAllowed = true
) )
.isEqualTo("Wrong password. Try again.") .isEqualTo("Wrong password. Try again.")
secondaryMessage( secondaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Password, mode = Password,
fpAllowedInBouncer = true fpAuthAllowed = true
) )
.isEqualTo("Or unlock with fingerprint") .isEqualTo("Or unlock with fingerprint")
primaryMessage( primaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Pattern, mode = Pattern,
fpAllowedInBouncer = true fpAuthAllowed = true
) )
.isEqualTo("Wrong pattern. Try again.") .isEqualTo("Wrong pattern. Try again.")
secondaryMessage( secondaryMessage(
PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
mode = Pattern, mode = Pattern,
fpAllowedInBouncer = true fpAuthAllowed = true
) )
.isEqualTo("Or unlock with fingerprint") .isEqualTo("Or unlock with fingerprint")
} }
@@ -123,11 +139,11 @@ class BouncerMessageFactoryTest : SysuiTestCase() {
private fun primaryMessage( private fun primaryMessage(
reason: Int, reason: Int,
mode: KeyguardSecurityModel.SecurityMode, mode: KeyguardSecurityModel.SecurityMode,
fpAllowedInBouncer: Boolean fpAuthAllowed: Boolean
): StringSubject { ): StringSubject {
return assertThat( return assertThat(
context.resources.getString( context.resources.getString(
bouncerMessageModel(mode, fpAllowedInBouncer, reason)!!.message!!.messageResId!! bouncerMessageModel(mode, fpAuthAllowed, reason)!!.message!!.messageResId!!
) )
)!! )!!
} }
@@ -135,25 +151,28 @@ class BouncerMessageFactoryTest : SysuiTestCase() {
private fun secondaryMessage( private fun secondaryMessage(
reason: Int, reason: Int,
mode: KeyguardSecurityModel.SecurityMode, mode: KeyguardSecurityModel.SecurityMode,
fpAllowedInBouncer: Boolean fpAuthAllowed: Boolean
): StringSubject { ): StringSubject {
return assertThat( return assertThat(
context.resources.getString( context.resources.getString(
bouncerMessageModel(mode, fpAllowedInBouncer, reason)!! bouncerMessageModel(mode, fpAuthAllowed, reason)!!.secondaryMessage!!.messageResId!!
.secondaryMessage!!
.messageResId!!
) )
)!! )!!
} }
private fun bouncerMessageModel( private fun bouncerMessageModel(
mode: KeyguardSecurityModel.SecurityMode, mode: KeyguardSecurityModel.SecurityMode,
fpAllowedInBouncer: Boolean, fpAuthAllowed: Boolean,
reason: Int reason: Int,
secondaryMessageOverride: String? = null,
): BouncerMessageModel? { ): BouncerMessageModel? {
whenever(securityModel.getSecurityMode(0)).thenReturn(mode) whenever(securityModel.getSecurityMode(0)).thenReturn(mode)
whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(fpAllowedInBouncer) whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(fpAuthAllowed)
return underTest.createFromPromptReason(reason, 0) return underTest.createFromPromptReason(
reason,
0,
secondaryMsgOverride = secondaryMessageOverride
)
} }
} }

View File

@@ -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.BouncerMessageModel
import com.android.systemui.bouncer.shared.model.Message import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.coroutines.collectLastValue 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.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository 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 updateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var securityModel: KeyguardSecurityModel @Mock private lateinit var securityModel: KeyguardSecurityModel
@Mock private lateinit var systemPropertiesHelper: SystemPropertiesHelper
@Captor @Captor
private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
@@ -99,7 +101,7 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository() fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository()
testScope = TestScope() testScope = TestScope()
whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(false) whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN) whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
underTest = underTest =
BouncerMessageRepositoryImpl( BouncerMessageRepositoryImpl(
@@ -108,7 +110,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
updateMonitor = updateMonitor, updateMonitor = updateMonitor,
bouncerMessageFactory = BouncerMessageFactory(updateMonitor, securityModel), bouncerMessageFactory = BouncerMessageFactory(updateMonitor, securityModel),
userRepository = userRepository, userRepository = userRepository,
fingerprintAuthRepository = fingerprintRepository fingerprintAuthRepository = fingerprintRepository,
systemPropertiesHelper = systemPropertiesHelper
) )
} }
@@ -213,6 +216,21 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
assertThat(lockedOutMessage()).isNull() 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 @Test
fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() = fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() =
testScope.runTest { testScope.runTest {
@@ -345,8 +363,8 @@ class BouncerMessageRepositoryTest : SysuiTestCase() {
private fun message(primaryResId: Int, secondaryResId: Int): BouncerMessageModel { private fun message(primaryResId: Int, secondaryResId: Int): BouncerMessageModel {
return BouncerMessageModel( return BouncerMessageModel(
message = Message(messageResId = primaryResId), message = Message(messageResId = primaryResId, animate = false),
secondaryMessage = Message(messageResId = secondaryResId) secondaryMessage = Message(messageResId = secondaryResId, animate = false)
) )
} }
private fun message(value: String): BouncerMessageModel { private fun message(value: String): BouncerMessageModel {

View File

@@ -76,7 +76,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
allowTestableLooperAsMainThread() allowTestableLooperAsMainThread()
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN) whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
whenever(updateMonitor.isFingerprintAllowedInBouncer).thenReturn(false) whenever(updateMonitor.isUnlockingWithFingerprintAllowed).thenReturn(false)
} }
suspend fun TestScope.init() { suspend fun TestScope.init() {
@@ -150,11 +150,12 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
underTest.setCustomMessage("not empty") underTest.setCustomMessage("not empty")
assertThat(repository.customMessage.value) val customMessage = repository.customMessage
.isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty"))) assertThat(customMessage.value!!.message!!.messageResId).isEqualTo(keyguard_enter_pin)
assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty")
underTest.setCustomMessage(null) underTest.setCustomMessage(null)
assertThat(repository.customMessage.value).isNull() assertThat(customMessage.value).isNull()
} }
@Test @Test
@@ -164,11 +165,15 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
underTest.setFaceAcquisitionMessage("not empty") underTest.setFaceAcquisitionMessage("not empty")
assertThat(repository.faceAcquisitionMessage.value) val faceAcquisitionMessage = repository.faceAcquisitionMessage
.isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty")))
assertThat(faceAcquisitionMessage.value!!.message!!.messageResId)
.isEqualTo(keyguard_enter_pin)
assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message)
.isEqualTo("not empty")
underTest.setFaceAcquisitionMessage(null) underTest.setFaceAcquisitionMessage(null)
assertThat(repository.faceAcquisitionMessage.value).isNull() assertThat(faceAcquisitionMessage.value).isNull()
} }
@Test @Test
@@ -178,11 +183,15 @@ class BouncerMessageInteractorTest : SysuiTestCase() {
underTest.setFingerprintAcquisitionMessage("not empty") underTest.setFingerprintAcquisitionMessage("not empty")
assertThat(repository.fingerprintAcquisitionMessage.value) val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage
.isEqualTo(BouncerMessageModel(secondaryMessage = Message(message = "not empty")))
assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId)
.isEqualTo(keyguard_enter_pin)
assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message)
.isEqualTo("not empty")
underTest.setFingerprintAcquisitionMessage(null) underTest.setFingerprintAcquisitionMessage(null)
assertThat(repository.fingerprintAcquisitionMessage.value).isNull() assertThat(fingerprintAcquisitionMessage.value).isNull()
} }
@Test @Test