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

Commit a1988d81 authored by burakov's avatar burakov
Browse files

[flexiglass] Disable the bouncer auto-confirm feature during throttling.

Fixes: 306520428
Test: Added new unit tests.
Test: Existing unit tests, integration tests and screenshot tests still
 pass.
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: I08e43fa8ca14d9a418e14dec4ebef20fdee78bab
parent 9b790b42
Loading
Loading
Loading
Loading
+3 −3
Original line number Original line Diff line number Diff line
@@ -65,7 +65,7 @@ interface AuthenticationRepository {
     * Note that the length of the PIN is also important to take into consideration, please see
     * Note that the length of the PIN is also important to take into consideration, please see
     * [hintedPinLength].
     * [hintedPinLength].
     */
     */
    val isAutoConfirmEnabled: StateFlow<Boolean>
    val isAutoConfirmFeatureEnabled: StateFlow<Boolean>


    /**
    /**
     * The exact length a PIN should be for us to enable PIN length hinting.
     * The exact length a PIN should be for us to enable PIN length hinting.
@@ -152,14 +152,14 @@ class AuthenticationRepositoryImpl
@Inject
@Inject
constructor(
constructor(
    @Application private val applicationScope: CoroutineScope,
    @Application private val applicationScope: CoroutineScope,
    private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
    private val userRepository: UserRepository,
    private val userRepository: UserRepository,
    private val lockPatternUtils: LockPatternUtils,
    private val lockPatternUtils: LockPatternUtils,
    broadcastDispatcher: BroadcastDispatcher,
    broadcastDispatcher: BroadcastDispatcher,
) : AuthenticationRepository {
) : AuthenticationRepository {


    override val isAutoConfirmEnabled: StateFlow<Boolean> =
    override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> =
        refreshingFlow(
        refreshingFlow(
            initialValue = false,
            initialValue = false,
            getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled,
            getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled,
+22 −4
Original line number Original line Diff line number Diff line
@@ -42,6 +42,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.stateIn
@@ -103,9 +104,29 @@ constructor(
                initialValue = throttling.value.remainingMs > 0,
                initialValue = throttling.value.remainingMs > 0,
            )
            )


    /**
     * Whether the auto confirm feature is enabled for the currently-selected user.
     *
     * Note that the length of the PIN is also important to take into consideration, please see
     * [hintedPinLength].
     *
     * During throttling, this is always disabled (`false`).
     */
    val isAutoConfirmEnabled: StateFlow<Boolean> =
        combine(repository.isAutoConfirmFeatureEnabled, isThrottled) { featureEnabled, isThrottled
                ->
                // Disable auto-confirm during throttling.
                featureEnabled && !isThrottled
            }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = false,
            )

    /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
    /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
    val hintedPinLength: StateFlow<Int?> =
    val hintedPinLength: StateFlow<Int?> =
        repository.isAutoConfirmEnabled
        isAutoConfirmEnabled
            .map { isAutoConfirmEnabled ->
            .map { isAutoConfirmEnabled ->
                repository.getPinLength().takeIf {
                repository.getPinLength().takeIf {
                    isAutoConfirmEnabled && it == repository.hintedPinLength
                    isAutoConfirmEnabled && it == repository.hintedPinLength
@@ -119,9 +140,6 @@ constructor(
                initialValue = null,
                initialValue = null,
            )
            )


    /** Whether the auto confirm feature is enabled for the currently-selected user. */
    val isAutoConfirmEnabled: StateFlow<Boolean> = repository.isAutoConfirmEnabled

    /** 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> = repository.isPatternVisible
    val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible


+2 −2
Original line number Original line Diff line number Diff line
@@ -100,12 +100,12 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    fun isAutoConfirmEnabled() =
    fun isAutoConfirmFeatureEnabled() =
        testScope.runTest {
        testScope.runTest {
            whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[0].id)).thenReturn(true)
            whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[0].id)).thenReturn(true)
            whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[1].id)).thenReturn(false)
            whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[1].id)).thenReturn(false)


            val values by collectValues(underTest.isAutoConfirmEnabled)
            val values by collectValues(underTest.isAutoConfirmFeatureEnabled)
            assertThat(values.first()).isFalse()
            assertThat(values.first()).isFalse()
            assertThat(values.last()).isTrue()
            assertThat(values.last()).isTrue()


+45 −9
Original line number Original line Diff line number Diff line
@@ -213,11 +213,14 @@ class AuthenticationInteractorTest : SysuiTestCase() {
    @Test
    @Test
    fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
    fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
        testScope.runTest {
        testScope.runTest {
            val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
            val isThrottled by collectLastValue(underTest.isThrottled)
            val isThrottled by collectLastValue(underTest.isThrottled)
            utils.authenticationRepository.apply {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(true)
                setAutoConfirmFeatureEnabled(true)
            }
            }
            assertThat(isAutoConfirmEnabled).isTrue()

            assertThat(
            assertThat(
                    underTest.authenticate(
                    underTest.authenticate(
                        FakeAuthenticationRepository.DEFAULT_PIN.toMutableList().apply {
                        FakeAuthenticationRepository.DEFAULT_PIN.toMutableList().apply {
@@ -233,10 +236,13 @@ class AuthenticationInteractorTest : SysuiTestCase() {
    @Test
    @Test
    fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
    fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
        testScope.runTest {
        testScope.runTest {
            val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
            utils.authenticationRepository.apply {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(true)
                setAutoConfirmFeatureEnabled(true)
            }
            }
            assertThat(isAutoConfirmEnabled).isTrue()

            assertThat(
            assertThat(
                    underTest.authenticate(
                    underTest.authenticate(
                        FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 },
                        FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 },
@@ -251,10 +257,13 @@ class AuthenticationInteractorTest : SysuiTestCase() {
    @Test
    @Test
    fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
    fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
        testScope.runTest {
        testScope.runTest {
            val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
            utils.authenticationRepository.apply {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(true)
                setAutoConfirmFeatureEnabled(true)
            }
            }
            assertThat(isAutoConfirmEnabled).isTrue()

            assertThat(
            assertThat(
                    underTest.authenticate(
                    underTest.authenticate(
                        FakeAuthenticationRepository.DEFAULT_PIN + listOf(7),
                        FakeAuthenticationRepository.DEFAULT_PIN + listOf(7),
@@ -269,10 +278,13 @@ class AuthenticationInteractorTest : SysuiTestCase() {
    @Test
    @Test
    fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
    fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
        testScope.runTest {
        testScope.runTest {
            val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
            utils.authenticationRepository.apply {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(true)
                setAutoConfirmFeatureEnabled(true)
            }
            }
            assertThat(isAutoConfirmEnabled).isTrue()

            assertThat(
            assertThat(
                    underTest.authenticate(
                    underTest.authenticate(
                        FakeAuthenticationRepository.DEFAULT_PIN,
                        FakeAuthenticationRepository.DEFAULT_PIN,
@@ -284,12 +296,36 @@ class AuthenticationInteractorTest : SysuiTestCase() {
            assertThat(isUnlocked).isTrue()
            assertThat(isUnlocked).isTrue()
        }
        }


    @Test
    fun tryAutoConfirm_withAutoConfirmCorrectPinButDuringThrottling_returnsNullAndHasNoEffects() =
        testScope.runTest {
            val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)
            val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked)
            val hintedPinLength by collectLastValue(underTest.hintedPinLength)
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmFeatureEnabled(true)
                setThrottleDuration(42)
            }

            val authResult =
                underTest.authenticate(
                    FakeAuthenticationRepository.DEFAULT_PIN,
                    tryAutoConfirm = true
                )

            assertThat(authResult).isEqualTo(AuthenticationResult.SKIPPED)
            assertThat(isAutoConfirmEnabled).isFalse()
            assertThat(isUnlocked).isFalse()
            assertThat(hintedPinLength).isNull()
        }

    @Test
    @Test
    fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
    fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
        testScope.runTest {
        testScope.runTest {
            utils.authenticationRepository.apply {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(false)
                setAutoConfirmFeatureEnabled(false)
            }
            }
            assertThat(
            assertThat(
                    underTest.authenticate(
                    underTest.authenticate(
@@ -416,7 +452,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
            val hintedPinLength by collectLastValue(underTest.hintedPinLength)
            val hintedPinLength by collectLastValue(underTest.hintedPinLength)
            utils.authenticationRepository.apply {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(false)
                setAutoConfirmFeatureEnabled(false)
            }
            }


            assertThat(hintedPinLength).isNull()
            assertThat(hintedPinLength).isNull()
@@ -433,7 +469,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
                        repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) }
                        repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) }
                    }
                    }
                )
                )
                setAutoConfirmEnabled(true)
                setAutoConfirmFeatureEnabled(true)
            }
            }


            assertThat(hintedPinLength).isNull()
            assertThat(hintedPinLength).isNull()
@@ -445,7 +481,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
            val hintedPinLength by collectLastValue(underTest.hintedPinLength)
            val hintedPinLength by collectLastValue(underTest.hintedPinLength)
            utils.authenticationRepository.apply {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(true)
                setAutoConfirmFeatureEnabled(true)
                overrideCredential(
                overrideCredential(
                    buildList {
                    buildList {
                        repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) }
                        repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) }
@@ -467,7 +503,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
                        repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) }
                        repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) }
                    }
                    }
                )
                )
                setAutoConfirmEnabled(true)
                setAutoConfirmFeatureEnabled(true)
            }
            }


            assertThat(hintedPinLength).isNull()
            assertThat(hintedPinLength).isNull()
+3 −1
Original line number Original line Diff line number Diff line
@@ -110,12 +110,14 @@ class BouncerInteractorTest : SysuiTestCase() {
        testScope.runTest {
        testScope.runTest {
            val currentScene by collectLastValue(sceneInteractor.desiredScene)
            val currentScene by collectLastValue(sceneInteractor.desiredScene)
            val message by collectLastValue(underTest.message)
            val message by collectLastValue(underTest.message)
            val isAutoConfirmEnabled by collectLastValue(underTest.isAutoConfirmEnabled)


            utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
            utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
            runCurrent()
            runCurrent()
            utils.authenticationRepository.setAutoConfirmEnabled(true)
            utils.authenticationRepository.setAutoConfirmFeatureEnabled(true)
            utils.deviceEntryRepository.setUnlocked(false)
            utils.deviceEntryRepository.setUnlocked(false)
            underTest.showOrUnlockDevice()
            underTest.showOrUnlockDevice()
            assertThat(isAutoConfirmEnabled).isTrue()
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
            assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
            assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
            underTest.clearMessage()
            underTest.clearMessage()
Loading