Merge changes Ibca81eed,I5539cdaf,I3f7029f5,I9ce0fe29,I59e48540, ... into udc-qpr-dev am: 36d7fcd6a3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24289207

Change-Id: If41810c5b0765042c095dc81a50c51799dc4a0ef
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Chandru S
2023-08-03 16:56:50 +00:00
committed by Automerger Merge Worker
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,8 +1082,10 @@ 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);
mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils, if (!mFeatureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) {
mSecurityModel.getSecurityMode(userId)); mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
mSecurityModel.getSecurityMode(userId));
}
} }
} }

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