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

Commit 9d8f520b authored by Alejandro Nijamkin's avatar Alejandro Nijamkin Committed by Ale Nijamkin
Browse files

[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
parent 71f14180
Loading
Loading
Loading
Loading
+20 −12
Original line number Diff line number Diff line
@@ -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",
+9 −0
Original line number Diff line number Diff line
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -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 {
+4 −0
Original line number Diff line number Diff line
@@ -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
+13 −0
Original line number Diff line number Diff line
@@ -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
Loading