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

Commit b21d149f authored by Chandru S's avatar Chandru S
Browse files

Avoid falsing rejections on PIN compose bouncer

Fixes: 361793132
Test: 1. Restart device or run adb shell setprop ctl.restart zygote
 2. Enable compose bouncer, set auth method as PIN
 3. Swipe up to bouncer
 4. Repeatedly tap any PIN button
 5. Bouncer should not get dimissed
Flag: com.android.systemui.compose_bouncer
Change-Id: I18678b36db3e0848b51836aebcb51f7350e85b02
parent fe993f7d
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.ui.composable

import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
@@ -49,6 +50,7 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -110,6 +112,7 @@ fun PinPad(
                onClicked = viewModel::onPinButtonClicked,
                scaling = buttonScaleAnimatables[index]::value,
                isAnimationEnabled = isDigitButtonAnimationEnabled,
                onPointerDown = viewModel::onDigitButtonDown,
            )
        }

@@ -133,6 +136,7 @@ fun PinPad(
            onClicked = viewModel::onPinButtonClicked,
            scaling = buttonScaleAnimatables[10]::value,
            isAnimationEnabled = isDigitButtonAnimationEnabled,
            onPointerDown = viewModel::onDigitButtonDown
        )

        ActionButton(
@@ -155,6 +159,7 @@ private fun DigitButton(
    digit: Int,
    isInputEnabled: Boolean,
    onClicked: (Int) -> Unit,
    onPointerDown: () -> Unit,
    scaling: () -> Float,
    isAnimationEnabled: Boolean,
) {
@@ -164,6 +169,7 @@ private fun DigitButton(
        backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
        foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant,
        isAnimationEnabled = isAnimationEnabled,
        onPointerDown = onPointerDown,
        modifier =
            Modifier.graphicsLayer {
                val scale = if (isAnimationEnabled) scaling() else 1f
@@ -235,6 +241,7 @@ private fun PinPadButton(
    isAnimationEnabled: Boolean,
    modifier: Modifier = Modifier,
    onLongPressed: (() -> Unit)? = null,
    onPointerDown: (() -> Unit)? = null,
    content: @Composable (contentColor: () -> Color) -> Unit,
) {
    val interactionSource = remember { MutableInteractionSource() }
@@ -308,6 +315,12 @@ private fun PinPadButton(
                            onClick = onClicked,
                            onLongClick = onLongPressed
                        )
                        .pointerInteropFilter { motionEvent ->
                            if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                                onPointerDown?.let { it() }
                            }
                            false
                        }
                },
    ) {
        content(contentColor::value)
+18 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.bouncer.ui.viewmodel

import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.KeyEvent.KEYCODE_0
import android.view.KeyEvent.KEYCODE_4
import android.view.KeyEvent.KEYCODE_A
@@ -31,6 +33,7 @@ import com.android.systemui.authentication.data.repository.fakeAuthenticationRep
import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.data.repository.fakeSimBouncerRepository
import com.android.systemui.classifier.fakeFalsingCollector
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
@@ -41,6 +44,7 @@ import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.random.Random
import kotlin.random.nextInt
import kotlin.test.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
@@ -60,12 +64,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
    private val testScope = kosmos.testScope
    private val sceneInteractor by lazy { kosmos.sceneInteractor }
    private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
    private val underTest =
    private val underTest by lazy {
        kosmos.pinBouncerViewModelFactory.create(
            isInputEnabled = MutableStateFlow(true),
            onIntentionalUserInput = {},
            authenticationMethod = AuthenticationMethodModel.Pin,
        )
    }

    @Before
    fun setUp() {
@@ -475,6 +480,18 @@ class PinBouncerViewModelTest : SysuiTestCase() {
            assertThat(pin).containsExactly(*expectedPin)
        }

    @Test
    @EnableFlags(com.android.systemui.Flags.FLAG_COMPOSE_BOUNCER)
    @DisableFlags(com.android.systemui.Flags.FLAG_SCENE_CONTAINER)
    fun onDigitButtonDown_avoidGesture_invoked() =
        testScope.runTest {
            lockDeviceAndOpenPinBouncer()

            underTest.onDigitButtonDown()

            assertTrue(kosmos.fakeFalsingCollector.wasLastGestureAvoided())
        }

    private fun TestScope.switchToScene(toScene: SceneKey) {
        val currentScene by collectLastValue(sceneInteractor.currentScene)
        val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
+10 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import com.android.keyguard.PinShapeAdapter
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
import com.android.systemui.res.R
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -265,6 +266,15 @@ constructor(
        }
    }

    /** Notifies that the user has pressed down on a digit button. */
    fun onDigitButtonDown() {
        if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
            // Current PIN bouncer informs FalsingInteractor#avoidGesture() upon every Pin button
            // touch.
            super.onDown()
        }
    }

    @AssistedFactory
    interface Factory {
        fun create(
+11 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import javax.inject.Inject;
public class FalsingCollectorFake implements FalsingCollector {

    public KeyEvent lastKeyEvent = null;
    public boolean avoidGestureInvoked = false;

    @Override
    public void init() {
@@ -87,6 +88,16 @@ public class FalsingCollectorFake implements FalsingCollector {

    @Override
    public void avoidGesture() {
        avoidGestureInvoked = true;
    }

    /**
     * @return whether {@link #avoidGesture()} was invoked.
     */
    public boolean wasLastGestureAvoided() {
        boolean wasLastGestureAvoided = avoidGestureInvoked;
        avoidGestureInvoked = false;
        return wasLastGestureAvoided;
    }

    @Override
+3 −1
Original line number Diff line number Diff line
@@ -18,4 +18,6 @@ package com.android.systemui.classifier

import com.android.systemui.kosmos.Kosmos

var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { FalsingCollectorFake() }
var Kosmos.fakeFalsingCollector by Kosmos.Fixture { FalsingCollectorFake() }

var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { fakeFalsingCollector }