summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alejandro Nijamkin <nijamkin@google.com> 2023-11-13 10:11:28 -0800
committer Ale Nijamkin <nijamkin@google.com> 2023-11-13 18:39:54 +0000
commit9d8f520bb77e30f7489dc3dee23dec93def1ec8d (patch)
tree9b6febf7c3abb719b420a9e462750ae65a2ca0c7
parent71f141800ea6c74f6098efd59bba97b43342116c (diff)
[flexiglass] Adds support for "enhanced PIN privacy"
Fix: 308977777 Test: unit tests added for repository and view-model Test: manully verified with the setting on and off that the digit buttons on the PIN bouncer don't and do animate when touched, respectively Test: manually verified that the setting value has no bearing on whether the non-digit buttons (delete and enter) are animated when touched: they always animate Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT Change-Id: Idf116b27ccd590a3f57bf6b6c35933ae2e3075d6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt12
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt8
8 files changed, 86 insertions, 12 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index fb50f69f7d9b..243751fafe5d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -76,6 +76,8 @@ fun PinPad(
val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState()
val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState()
val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
+ val isDigitButtonAnimationEnabled: Boolean by
+ viewModel.isDigitButtonAnimationEnabled.collectAsState()
val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } }
LaunchedEffect(animateFailure) {
@@ -94,10 +96,11 @@ fun PinPad(
) {
repeat(9) { index ->
DigitButton(
- index + 1,
- isInputEnabled,
- viewModel::onPinButtonClicked,
- buttonScaleAnimatables[index]::value,
+ digit = index + 1,
+ isInputEnabled = isInputEnabled,
+ onClicked = viewModel::onPinButtonClicked,
+ scaling = buttonScaleAnimatables[index]::value,
+ isAnimationEnabled = isDigitButtonAnimationEnabled,
)
}
@@ -116,10 +119,11 @@ fun PinPad(
)
DigitButton(
- 0,
- isInputEnabled,
- viewModel::onPinButtonClicked,
- buttonScaleAnimatables[10]::value,
+ digit = 0,
+ isInputEnabled = isInputEnabled,
+ onClicked = viewModel::onPinButtonClicked,
+ scaling = buttonScaleAnimatables[10]::value,
+ isAnimationEnabled = isDigitButtonAnimationEnabled,
)
ActionButton(
@@ -143,15 +147,17 @@ private fun DigitButton(
isInputEnabled: Boolean,
onClicked: (Int) -> Unit,
scaling: () -> Float,
+ isAnimationEnabled: Boolean,
) {
PinPadButton(
onClicked = { onClicked(digit) },
isEnabled = isInputEnabled,
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant,
+ isAnimationEnabled = isAnimationEnabled,
modifier =
Modifier.graphicsLayer {
- val scale = scaling()
+ val scale = if (isAnimationEnabled) scaling() else 1f
scaleX = scale
scaleY = scale
}
@@ -195,6 +201,7 @@ private fun ActionButton(
isEnabled = isInputEnabled && !isHidden,
backgroundColor = backgroundColor,
foregroundColor = foregroundColor,
+ isAnimationEnabled = true,
modifier =
Modifier.graphicsLayer {
alpha = hiddenAlpha
@@ -216,6 +223,7 @@ private fun PinPadButton(
isEnabled: Boolean,
backgroundColor: Color,
foregroundColor: Color,
+ isAnimationEnabled: Boolean,
modifier: Modifier = Modifier,
onLongPressed: (() -> Unit)? = null,
content: @Composable (contentColor: () -> Color) -> Unit,
@@ -243,7 +251,7 @@ private fun PinPadButton(
val cornerRadius: Dp by
animateDpAsState(
- if (isPressed) 24.dp else pinButtonSize / 2,
+ if (isAnimationEnabled && isPressed) 24.dp else pinButtonSize / 2,
label = "PinButton round corners",
animationSpec = tween(animDurationMillis, easing = animEasing)
)
@@ -251,7 +259,7 @@ private fun PinPadButton(
val containerColor: Color by
animateColorAsState(
when {
- isPressed -> MaterialTheme.colorScheme.primary
+ isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.primary
else -> backgroundColor
},
label = "Pin button container color",
@@ -260,7 +268,7 @@ private fun PinPadButton(
val contentColor =
animateColorAsState(
when {
- isPressed -> MaterialTheme.colorScheme.onPrimary
+ isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.onPrimary
else -> foregroundColor
},
label = "Pin button container color",
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index ee3a55f51679..7769dd9dc9ab 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -108,6 +108,9 @@ interface AuthenticationRepository {
/** The minimal length of a pattern. */
val minPatternLength: Int
+ /** Whether the "enhanced PIN privacy" setting is enabled for the current user. */
+ val isPinEnhancedPrivacyEnabled: StateFlow<Boolean>
+
/**
* Returns the currently-configured authentication method. This determines how the
* authentication challenge needs to be completed in order to unlock an otherwise locked device.
@@ -212,6 +215,12 @@ constructor(
override val minPatternLength: Int = LockPatternUtils.MIN_LOCK_PATTERN_SIZE
+ override val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> =
+ refreshingFlow(
+ initialValue = true,
+ getFreshValue = { userId -> lockPatternUtils.isPinEnhancedPrivacyEnabled(userId) },
+ )
+
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return withContext(backgroundDispatcher) {
blockingAuthenticationMethodInternal(userRepository.selectedUserId)
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 1ede5301e751..5eefbf5353d3 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -145,6 +145,9 @@ constructor(
val authenticationChallengeResult: SharedFlow<Boolean> =
repository.authenticationChallengeResult
+ /** Whether the "enhanced PIN privacy" setting is enabled for the current user. */
+ val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> = repository.isPinEnhancedPrivacyEnabled
+
private var throttlingCountdownJob: Job? = null
init {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 4e1cddc63530..ff36839460be 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -92,6 +92,10 @@ constructor(
/** Whether the pattern should be visible for the currently-selected user. */
val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible
+ /** Whether the "enhanced PIN privacy" setting is enabled for the current user. */
+ val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> =
+ authenticationInteractor.isPinEnhancedPrivacyEnabled
+
/** Whether the user switcher should be displayed within the bouncer UI on large screens. */
val isUserSwitcherVisible: Boolean
get() = repository.isUserSwitcherVisible
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 2ed0d5d2f6c1..b2b8049e3cff 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -84,6 +84,19 @@ class PinBouncerViewModel(
override val throttlingMessageId = R.string.kg_too_many_failed_pin_attempts_dialog_message
+ /**
+ * Whether the digit buttons should be animated when touched. Note that this doesn't affect the
+ * delete or enter buttons; those should always animate.
+ */
+ val isDigitButtonAnimationEnabled: StateFlow<Boolean> =
+ interactor.isPinEnhancedPrivacyEnabled
+ .map { !it }
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = !interactor.isPinEnhancedPrivacyEnabled.value,
+ )
+
/** Notifies that the user clicked on a PIN button with the given digit value. */
fun onPinButtonClicked(input: Int) {
val pinInput = mutablePinInput.value
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
index ae2ec2ca1fe9..87ab5b0d157f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
@@ -143,6 +143,23 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
assertThat(authenticationChallengeResults).isEqualTo(listOf(true, false, true))
}
+ @Test
+ fun isPinEnhancedPrivacyEnabled() =
+ testScope.runTest {
+ whenever(lockPatternUtils.isPinEnhancedPrivacyEnabled(USER_INFOS[0].id))
+ .thenReturn(false)
+ whenever(lockPatternUtils.isPinEnhancedPrivacyEnabled(USER_INFOS[1].id))
+ .thenReturn(true)
+
+ val values by collectValues(underTest.isPinEnhancedPrivacyEnabled)
+ assertThat(values.first()).isTrue()
+ assertThat(values.last()).isFalse()
+
+ userRepository.setSelectedUserInfo(USER_INFOS[1])
+ assertThat(values.last()).isTrue()
+
+ }
+
private fun setSecurityModeAndDispatchBroadcast(
securityMode: KeyguardSecurityModel.SecurityMode,
) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 6da69519000c..7a9cb6cc18c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -354,6 +354,18 @@ class PinBouncerViewModelTest : SysuiTestCase() {
assertThat(confirmButtonAppearance).isEqualTo(ActionButtonAppearance.Hidden)
}
+ @Test
+ fun isDigitButtonAnimationEnabled() =
+ testScope.runTest {
+ val isAnimationEnabled by collectLastValue(underTest.isDigitButtonAnimationEnabled)
+
+ utils.authenticationRepository.setPinEnhancedPrivacyEnabled(true)
+ assertThat(isAnimationEnabled).isFalse()
+
+ utils.authenticationRepository.setPinEnhancedPrivacyEnabled(false)
+ assertThat(isAnimationEnabled).isTrue()
+ }
+
private fun TestScope.lockDeviceAndOpenPinBouncer() {
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.deviceEntryRepository.setUnlocked(false)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
index 6e9363b744ab..af1930ef143e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -60,6 +60,10 @@ class FakeAuthenticationRepository(
override val minPatternLength: Int = 4
+ private val _isPinEnhancedPrivacyEnabled = MutableStateFlow(false)
+ override val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> =
+ _isPinEnhancedPrivacyEnabled.asStateFlow()
+
private var failedAttemptCount = 0
private var throttlingEndTimestamp = 0L
private var credentialOverride: List<Any>? = null
@@ -138,6 +142,10 @@ class FakeAuthenticationRepository(
}
}
+ fun setPinEnhancedPrivacyEnabled(isEnabled: Boolean) {
+ _isPinEnhancedPrivacyEnabled.value = isEnabled
+ }
+
private fun getExpectedCredential(securityMode: SecurityMode): List<Any> {
return when (val credentialType = getCurrentCredentialType(securityMode)) {
LockPatternUtils.CREDENTIAL_TYPE_PIN -> credentialOverride ?: DEFAULT_PIN