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

Commit a732e6e2 authored by Danny Burakov's avatar Danny Burakov Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Disable the bouncer auto-confirm feature during throttling." into main

parents 3aa4ceb2 a1988d81
Loading
Loading
Loading
Loading
+3 −3
Original line number 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
     * [hintedPinLength].
     */
    val isAutoConfirmEnabled: StateFlow<Boolean>
    val isAutoConfirmFeatureEnabled: StateFlow<Boolean>

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

    override val isAutoConfirmEnabled: StateFlow<Boolean> =
    override val isAutoConfirmFeatureEnabled: StateFlow<Boolean> =
        refreshingFlow(
            initialValue = false,
            getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled,
+22 −4
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -103,9 +104,29 @@ constructor(
                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. */
    val hintedPinLength: StateFlow<Int?> =
        repository.isAutoConfirmEnabled
        isAutoConfirmEnabled
            .map { isAutoConfirmEnabled ->
                repository.getPinLength().takeIf {
                    isAutoConfirmEnabled && it == repository.hintedPinLength
@@ -119,9 +140,6 @@ constructor(
                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. */
    val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible

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

    @Test
    fun isAutoConfirmEnabled() =
    fun isAutoConfirmFeatureEnabled() =
        testScope.runTest {
            whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[0].id)).thenReturn(true)
            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.last()).isTrue()

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

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

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

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

            assertThat(
                    underTest.authenticate(
                        FakeAuthenticationRepository.DEFAULT_PIN,
@@ -284,12 +296,36 @@ class AuthenticationInteractorTest : SysuiTestCase() {
            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
    fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
        testScope.runTest {
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(false)
                setAutoConfirmFeatureEnabled(false)
            }
            assertThat(
                    underTest.authenticate(
@@ -416,7 +452,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
            val hintedPinLength by collectLastValue(underTest.hintedPinLength)
            utils.authenticationRepository.apply {
                setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
                setAutoConfirmEnabled(false)
                setAutoConfirmFeatureEnabled(false)
            }

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

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

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

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