Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03db21e7 authored by Mike Schneider's avatar Mike Schneider Committed by Automerger Merge Worker
Browse files

Merge changes from topic "autoconfirm" into udc-qpr-dev am: e0abf262

parents 7a47e2df e0abf262
Loading
Loading
Loading
Loading
+76 −16
Original line number Diff line number Diff line
@@ -21,7 +21,9 @@ package com.android.systemui.bouncer.ui.composable
import android.view.HapticFeedbackConstants
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateDp
@@ -79,6 +81,7 @@ import com.android.systemui.compose.modifiers.thenIf
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@@ -90,16 +93,6 @@ internal fun PinBouncer(
    // Report that the UI is shown to let the view-model run some logic.
    LaunchedEffect(Unit) { viewModel.onShown() }

    val animateFailure: Boolean by viewModel.animateFailure.collectAsState()

    // Show the failure animation if the user entered the wrong input.
    LaunchedEffect(animateFailure) {
        if (animateFailure) {
            showFailureAnimation()
            viewModel.onFailureAnimationShown()
        }
    }

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = modifier,
@@ -257,13 +250,30 @@ private fun PinPad(viewModel: PinBouncerViewModel) {
    val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
    val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState()
    val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState()
    val animateFailure: Boolean by viewModel.animateFailure.collectAsState()

    val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } }
    LaunchedEffect(animateFailure) {
        // Show the failure animation if the user entered the wrong input.
        if (animateFailure) {
            showFailureAnimation(buttonScaleAnimatables)
            viewModel.onFailureAnimationShown()
        }
    }

    VerticalGrid(
        columns = 3,
        verticalSpacing = 12.dp,
        horizontalSpacing = 20.dp,
    ) {
        repeat(9) { index -> DigitButton(index + 1, isInputEnabled, viewModel::onPinButtonClicked) }
        repeat(9) { index ->
            DigitButton(
                index + 1,
                isInputEnabled,
                viewModel::onPinButtonClicked,
                buttonScaleAnimatables[index]::value,
            )
        }

        ActionButton(
            icon =
@@ -276,9 +286,15 @@ private fun PinPad(viewModel: PinBouncerViewModel) {
            onClicked = viewModel::onBackspaceButtonClicked,
            onLongPressed = viewModel::onBackspaceButtonLongPressed,
            appearance = backspaceButtonAppearance,
            scaling = buttonScaleAnimatables[9]::value,
        )

        DigitButton(0, isInputEnabled, viewModel::onPinButtonClicked)
        DigitButton(
            0,
            isInputEnabled,
            viewModel::onPinButtonClicked,
            buttonScaleAnimatables[10]::value,
        )

        ActionButton(
            icon =
@@ -289,7 +305,8 @@ private fun PinPad(viewModel: PinBouncerViewModel) {
                ),
            isInputEnabled = isInputEnabled,
            onClicked = viewModel::onAuthenticateButtonClicked,
            appearance = confirmButtonAppearance
            appearance = confirmButtonAppearance,
            scaling = buttonScaleAnimatables[11]::value,
        )
    }
}
@@ -299,12 +316,19 @@ private fun DigitButton(
    digit: Int,
    isInputEnabled: Boolean,
    onClicked: (Int) -> Unit,
    scaling: () -> Float,
) {
    PinPadButton(
        onClicked = { onClicked(digit) },
        isEnabled = isInputEnabled,
        backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
        foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant,
        modifier =
            Modifier.graphicsLayer {
                val scale = scaling()
                scaleX = scale
                scaleY = scale
            }
    ) { contentColor ->
        // TODO(b/281878426): once "color: () -> Color" (added to BasicText in aosp/2568972) makes
        // it into Text, use that here, to animate more efficiently.
@@ -323,6 +347,7 @@ private fun ActionButton(
    onClicked: () -> Unit,
    onLongPressed: (() -> Unit)? = null,
    appearance: ActionButtonAppearance,
    scaling: () -> Float,
) {
    val isHidden = appearance == ActionButtonAppearance.Hidden
    val hiddenAlpha by animateFloatAsState(if (isHidden) 0f else 1f, label = "Action button alpha")
@@ -344,7 +369,13 @@ private fun ActionButton(
        isEnabled = isInputEnabled && !isHidden,
        backgroundColor = backgroundColor,
        foregroundColor = foregroundColor,
        modifier = Modifier.graphicsLayer { alpha = hiddenAlpha }
        modifier =
            Modifier.graphicsLayer {
                alpha = hiddenAlpha
                val scale = scaling()
                scaleX = scale
                scaleY = scale
            }
    ) { contentColor ->
        Icon(
            icon = icon,
@@ -447,13 +478,42 @@ private fun PinPadButton(
    }
}

private fun showFailureAnimation() {
    // TODO(b/282730134): implement.
private suspend fun showFailureAnimation(
    buttonScaleAnimatables: List<Animatable<Float, AnimationVector1D>>
) {
    coroutineScope {
        buttonScaleAnimatables.forEachIndexed { index, animatable ->
            launch {
                animatable.animateTo(
                    targetValue = pinButtonErrorShrinkFactor,
                    animationSpec =
                        tween(
                            durationMillis = pinButtonErrorShrinkMs,
                            delayMillis = index * pinButtonErrorStaggerDelayMs,
                            easing = Easings.Linear,
                        ),
                )

                animatable.animateTo(
                    targetValue = 1f,
                    animationSpec =
                        tween(
                            durationMillis = pinButtonErrorRevertMs,
                            easing = Easings.Legacy,
                        ),
                )
            }
        }
    }
}

private val entryShapeSize = 16.dp

private val pinButtonSize = 84.dp
private val pinButtonErrorShrinkFactor = 67.dp / pinButtonSize
private const val pinButtonErrorShrinkMs = 50
private const val pinButtonErrorStaggerDelayMs = 33
private const val pinButtonErrorRevertMs = 617

// Pin button motion spec: http://shortn/_9TTIG6SoEa
private val pinButtonPressedDuration = 100.milliseconds