Loading packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt +20 −12 Original line number Original line Diff line number Diff line Loading @@ -76,6 +76,8 @@ fun PinPad( val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState() val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState() val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState() val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState() val animateFailure: Boolean by viewModel.animateFailure.collectAsState() val animateFailure: Boolean by viewModel.animateFailure.collectAsState() val isDigitButtonAnimationEnabled: Boolean by viewModel.isDigitButtonAnimationEnabled.collectAsState() val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } } val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } } LaunchedEffect(animateFailure) { LaunchedEffect(animateFailure) { Loading @@ -94,10 +96,11 @@ fun PinPad( ) { ) { repeat(9) { index -> repeat(9) { index -> DigitButton( DigitButton( index + 1, digit = index + 1, isInputEnabled, isInputEnabled = isInputEnabled, viewModel::onPinButtonClicked, onClicked = viewModel::onPinButtonClicked, buttonScaleAnimatables[index]::value, scaling = buttonScaleAnimatables[index]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, ) ) } } Loading @@ -116,10 +119,11 @@ fun PinPad( ) ) DigitButton( DigitButton( 0, digit = 0, isInputEnabled, isInputEnabled = isInputEnabled, viewModel::onPinButtonClicked, onClicked = viewModel::onPinButtonClicked, buttonScaleAnimatables[10]::value, scaling = buttonScaleAnimatables[10]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, ) ) ActionButton( ActionButton( Loading @@ -143,15 +147,17 @@ private fun DigitButton( isInputEnabled: Boolean, isInputEnabled: Boolean, onClicked: (Int) -> Unit, onClicked: (Int) -> Unit, scaling: () -> Float, scaling: () -> Float, isAnimationEnabled: Boolean, ) { ) { PinPadButton( PinPadButton( onClicked = { onClicked(digit) }, onClicked = { onClicked(digit) }, isEnabled = isInputEnabled, isEnabled = isInputEnabled, backgroundColor = MaterialTheme.colorScheme.surfaceVariant, backgroundColor = MaterialTheme.colorScheme.surfaceVariant, foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant, foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant, isAnimationEnabled = isAnimationEnabled, modifier = modifier = Modifier.graphicsLayer { Modifier.graphicsLayer { val scale = scaling() val scale = if (isAnimationEnabled) scaling() else 1f scaleX = scale scaleX = scale scaleY = scale scaleY = scale } } Loading Loading @@ -195,6 +201,7 @@ private fun ActionButton( isEnabled = isInputEnabled && !isHidden, isEnabled = isInputEnabled && !isHidden, backgroundColor = backgroundColor, backgroundColor = backgroundColor, foregroundColor = foregroundColor, foregroundColor = foregroundColor, isAnimationEnabled = true, modifier = modifier = Modifier.graphicsLayer { Modifier.graphicsLayer { alpha = hiddenAlpha alpha = hiddenAlpha Loading @@ -216,6 +223,7 @@ private fun PinPadButton( isEnabled: Boolean, isEnabled: Boolean, backgroundColor: Color, backgroundColor: Color, foregroundColor: Color, foregroundColor: Color, isAnimationEnabled: Boolean, modifier: Modifier = Modifier, modifier: Modifier = Modifier, onLongPressed: (() -> Unit)? = null, onLongPressed: (() -> Unit)? = null, content: @Composable (contentColor: () -> Color) -> Unit, content: @Composable (contentColor: () -> Color) -> Unit, Loading Loading @@ -243,7 +251,7 @@ private fun PinPadButton( val cornerRadius: Dp by val cornerRadius: Dp by animateDpAsState( animateDpAsState( if (isPressed) 24.dp else pinButtonSize / 2, if (isAnimationEnabled && isPressed) 24.dp else pinButtonSize / 2, label = "PinButton round corners", label = "PinButton round corners", animationSpec = tween(animDurationMillis, easing = animEasing) animationSpec = tween(animDurationMillis, easing = animEasing) ) ) Loading @@ -251,7 +259,7 @@ private fun PinPadButton( val containerColor: Color by val containerColor: Color by animateColorAsState( animateColorAsState( when { when { isPressed -> MaterialTheme.colorScheme.primary isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.primary else -> backgroundColor else -> backgroundColor }, }, label = "Pin button container color", label = "Pin button container color", Loading @@ -260,7 +268,7 @@ private fun PinPadButton( val contentColor = val contentColor = animateColorAsState( animateColorAsState( when { when { isPressed -> MaterialTheme.colorScheme.onPrimary isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.onPrimary else -> foregroundColor else -> foregroundColor }, }, label = "Pin button container color", label = "Pin button container color", Loading packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,9 @@ interface AuthenticationRepository { /** The minimal length of a pattern. */ /** The minimal length of a pattern. */ val minPatternLength: Int 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 * Returns the currently-configured authentication method. This determines how the * authentication challenge needs to be completed in order to unlock an otherwise locked device. * authentication challenge needs to be completed in order to unlock an otherwise locked device. Loading Loading @@ -212,6 +215,12 @@ constructor( override val minPatternLength: Int = LockPatternUtils.MIN_LOCK_PATTERN_SIZE 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 { override suspend fun getAuthenticationMethod(): AuthenticationMethodModel { return withContext(backgroundDispatcher) { return withContext(backgroundDispatcher) { blockingAuthenticationMethodInternal(userRepository.selectedUserId) blockingAuthenticationMethodInternal(userRepository.selectedUserId) Loading packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +3 −0 Original line number Original line Diff line number Diff line Loading @@ -145,6 +145,9 @@ constructor( val authenticationChallengeResult: SharedFlow<Boolean> = val authenticationChallengeResult: SharedFlow<Boolean> = repository.authenticationChallengeResult 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 private var throttlingCountdownJob: Job? = null init { init { Loading packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -92,6 +92,10 @@ constructor( /** Whether the pattern should be visible for the currently-selected user. */ /** Whether the pattern should be visible for the currently-selected user. */ val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible 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. */ /** Whether the user switcher should be displayed within the bouncer UI on large screens. */ val isUserSwitcherVisible: Boolean val isUserSwitcherVisible: Boolean get() = repository.isUserSwitcherVisible get() = repository.isUserSwitcherVisible Loading packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +13 −0 Original line number Original line Diff line number Diff line Loading @@ -84,6 +84,19 @@ class PinBouncerViewModel( override val throttlingMessageId = R.string.kg_too_many_failed_pin_attempts_dialog_message 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. */ /** Notifies that the user clicked on a PIN button with the given digit value. */ fun onPinButtonClicked(input: Int) { fun onPinButtonClicked(input: Int) { val pinInput = mutablePinInput.value val pinInput = mutablePinInput.value Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt +20 −12 Original line number Original line Diff line number Diff line Loading @@ -76,6 +76,8 @@ fun PinPad( val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState() val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState() val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState() val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState() val animateFailure: Boolean by viewModel.animateFailure.collectAsState() val animateFailure: Boolean by viewModel.animateFailure.collectAsState() val isDigitButtonAnimationEnabled: Boolean by viewModel.isDigitButtonAnimationEnabled.collectAsState() val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } } val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } } LaunchedEffect(animateFailure) { LaunchedEffect(animateFailure) { Loading @@ -94,10 +96,11 @@ fun PinPad( ) { ) { repeat(9) { index -> repeat(9) { index -> DigitButton( DigitButton( index + 1, digit = index + 1, isInputEnabled, isInputEnabled = isInputEnabled, viewModel::onPinButtonClicked, onClicked = viewModel::onPinButtonClicked, buttonScaleAnimatables[index]::value, scaling = buttonScaleAnimatables[index]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, ) ) } } Loading @@ -116,10 +119,11 @@ fun PinPad( ) ) DigitButton( DigitButton( 0, digit = 0, isInputEnabled, isInputEnabled = isInputEnabled, viewModel::onPinButtonClicked, onClicked = viewModel::onPinButtonClicked, buttonScaleAnimatables[10]::value, scaling = buttonScaleAnimatables[10]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, ) ) ActionButton( ActionButton( Loading @@ -143,15 +147,17 @@ private fun DigitButton( isInputEnabled: Boolean, isInputEnabled: Boolean, onClicked: (Int) -> Unit, onClicked: (Int) -> Unit, scaling: () -> Float, scaling: () -> Float, isAnimationEnabled: Boolean, ) { ) { PinPadButton( PinPadButton( onClicked = { onClicked(digit) }, onClicked = { onClicked(digit) }, isEnabled = isInputEnabled, isEnabled = isInputEnabled, backgroundColor = MaterialTheme.colorScheme.surfaceVariant, backgroundColor = MaterialTheme.colorScheme.surfaceVariant, foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant, foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant, isAnimationEnabled = isAnimationEnabled, modifier = modifier = Modifier.graphicsLayer { Modifier.graphicsLayer { val scale = scaling() val scale = if (isAnimationEnabled) scaling() else 1f scaleX = scale scaleX = scale scaleY = scale scaleY = scale } } Loading Loading @@ -195,6 +201,7 @@ private fun ActionButton( isEnabled = isInputEnabled && !isHidden, isEnabled = isInputEnabled && !isHidden, backgroundColor = backgroundColor, backgroundColor = backgroundColor, foregroundColor = foregroundColor, foregroundColor = foregroundColor, isAnimationEnabled = true, modifier = modifier = Modifier.graphicsLayer { Modifier.graphicsLayer { alpha = hiddenAlpha alpha = hiddenAlpha Loading @@ -216,6 +223,7 @@ private fun PinPadButton( isEnabled: Boolean, isEnabled: Boolean, backgroundColor: Color, backgroundColor: Color, foregroundColor: Color, foregroundColor: Color, isAnimationEnabled: Boolean, modifier: Modifier = Modifier, modifier: Modifier = Modifier, onLongPressed: (() -> Unit)? = null, onLongPressed: (() -> Unit)? = null, content: @Composable (contentColor: () -> Color) -> Unit, content: @Composable (contentColor: () -> Color) -> Unit, Loading Loading @@ -243,7 +251,7 @@ private fun PinPadButton( val cornerRadius: Dp by val cornerRadius: Dp by animateDpAsState( animateDpAsState( if (isPressed) 24.dp else pinButtonSize / 2, if (isAnimationEnabled && isPressed) 24.dp else pinButtonSize / 2, label = "PinButton round corners", label = "PinButton round corners", animationSpec = tween(animDurationMillis, easing = animEasing) animationSpec = tween(animDurationMillis, easing = animEasing) ) ) Loading @@ -251,7 +259,7 @@ private fun PinPadButton( val containerColor: Color by val containerColor: Color by animateColorAsState( animateColorAsState( when { when { isPressed -> MaterialTheme.colorScheme.primary isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.primary else -> backgroundColor else -> backgroundColor }, }, label = "Pin button container color", label = "Pin button container color", Loading @@ -260,7 +268,7 @@ private fun PinPadButton( val contentColor = val contentColor = animateColorAsState( animateColorAsState( when { when { isPressed -> MaterialTheme.colorScheme.onPrimary isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.onPrimary else -> foregroundColor else -> foregroundColor }, }, label = "Pin button container color", label = "Pin button container color", Loading
packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,9 @@ interface AuthenticationRepository { /** The minimal length of a pattern. */ /** The minimal length of a pattern. */ val minPatternLength: Int 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 * Returns the currently-configured authentication method. This determines how the * authentication challenge needs to be completed in order to unlock an otherwise locked device. * authentication challenge needs to be completed in order to unlock an otherwise locked device. Loading Loading @@ -212,6 +215,12 @@ constructor( override val minPatternLength: Int = LockPatternUtils.MIN_LOCK_PATTERN_SIZE 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 { override suspend fun getAuthenticationMethod(): AuthenticationMethodModel { return withContext(backgroundDispatcher) { return withContext(backgroundDispatcher) { blockingAuthenticationMethodInternal(userRepository.selectedUserId) blockingAuthenticationMethodInternal(userRepository.selectedUserId) Loading
packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +3 −0 Original line number Original line Diff line number Diff line Loading @@ -145,6 +145,9 @@ constructor( val authenticationChallengeResult: SharedFlow<Boolean> = val authenticationChallengeResult: SharedFlow<Boolean> = repository.authenticationChallengeResult 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 private var throttlingCountdownJob: Job? = null init { init { Loading
packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -92,6 +92,10 @@ constructor( /** Whether the pattern should be visible for the currently-selected user. */ /** Whether the pattern should be visible for the currently-selected user. */ val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible 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. */ /** Whether the user switcher should be displayed within the bouncer UI on large screens. */ val isUserSwitcherVisible: Boolean val isUserSwitcherVisible: Boolean get() = repository.isUserSwitcherVisible get() = repository.isUserSwitcherVisible Loading
packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +13 −0 Original line number Original line Diff line number Diff line Loading @@ -84,6 +84,19 @@ class PinBouncerViewModel( override val throttlingMessageId = R.string.kg_too_many_failed_pin_attempts_dialog_message 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. */ /** Notifies that the user clicked on a PIN button with the given digit value. */ fun onPinButtonClicked(input: Int) { fun onPinButtonClicked(input: Int) { val pinInput = mutablePinInput.value val pinInput = mutablePinInput.value Loading