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

Commit 7f022c65 authored by burakov's avatar burakov
Browse files

[flexiglass] Reset PIN and Password on the bouncer when it's re-shown.

Fix: 291999047
Test: Added unit tests, existing ones still pass.
Test: Manually tested on a device following the repo steps on the
associated bug, observed that the bug doesn't reproduce due to the fix.

Change-Id: I285d15d862c3b7cacd1432bf20278a292ff4cd8d
parent 90806496
Loading
Loading
Loading
Loading
+5 −4
Original line number Original line Diff line number Diff line
@@ -40,20 +40,21 @@ class PasswordBouncerViewModel(


    /** Notifies that the UI has been shown to the user. */
    /** Notifies that the UI has been shown to the user. */
    fun onShown() {
    fun onShown() {
        _password.value = ""
        interactor.resetMessage()
        interactor.resetMessage()
    }
    }


    /** Notifies that the user has changed the password input. */
    /** Notifies that the user has changed the password input. */
    fun onPasswordInputChanged(password: String) {
    fun onPasswordInputChanged(newPassword: String) {
        if (this.password.value.isEmpty() && password.isNotEmpty()) {
        if (this.password.value.isEmpty() && newPassword.isNotEmpty()) {
            interactor.clearMessage()
            interactor.clearMessage()
        }
        }


        if (password.isNotEmpty()) {
        if (newPassword.isNotEmpty()) {
            interactor.onIntentionalUserInput()
            interactor.onIntentionalUserInput()
        }
        }


        _password.value = password
        _password.value = newPassword
    }
    }


    /** Notifies that the user has pressed the key for attempting to authenticate the password. */
    /** Notifies that the user has pressed the key for attempting to authenticate the password. */
+8 −9
Original line number Original line Diff line number Diff line
@@ -70,13 +70,7 @@ class PinBouncerViewModel(
    /** Appearance of the confirm button. */
    /** Appearance of the confirm button. */
    val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
    val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
        interactor.isAutoConfirmEnabled
        interactor.isAutoConfirmEnabled
            .map {
            .map { if (it) ActionButtonAppearance.Hidden else ActionButtonAppearance.Shown }
                if (it) {
                    ActionButtonAppearance.Hidden
                } else {
                    ActionButtonAppearance.Shown
                }
            }
            .stateIn(
            .stateIn(
                scope = applicationScope,
                scope = applicationScope,
                started = SharingStarted.Eagerly,
                started = SharingStarted.Eagerly,
@@ -85,6 +79,7 @@ class PinBouncerViewModel(


    /** Notifies that the UI has been shown to the user. */
    /** Notifies that the UI has been shown to the user. */
    fun onShown() {
    fun onShown() {
        clearPinInput()
        interactor.resetMessage()
        interactor.resetMessage()
    }
    }


@@ -113,7 +108,7 @@ class PinBouncerViewModel(


    /** Notifies that the user long-pressed the backspace button. */
    /** Notifies that the user long-pressed the backspace button. */
    fun onBackspaceButtonLongPressed() {
    fun onBackspaceButtonLongPressed() {
        mutablePinInput.value = mutablePinInput.value.clearAll()
        clearPinInput()
    }
    }


    /** Notifies that the user clicked the "enter" button. */
    /** Notifies that the user clicked the "enter" button. */
@@ -121,6 +116,10 @@ class PinBouncerViewModel(
        tryAuthenticate(useAutoConfirm = false)
        tryAuthenticate(useAutoConfirm = false)
    }
    }


    private fun clearPinInput() {
        mutablePinInput.value = mutablePinInput.value.clearAll()
    }

    private fun tryAuthenticate(useAutoConfirm: Boolean) {
    private fun tryAuthenticate(useAutoConfirm: Boolean) {
        val pinCode = mutablePinInput.value.getPin()
        val pinCode = mutablePinInput.value.getPin()


@@ -133,7 +132,7 @@ class PinBouncerViewModel(


            // TODO(b/291528545): this should not be cleared on success (at least until the view
            // TODO(b/291528545): this should not be cleared on success (at least until the view
            // is animated away).
            // is animated away).
            mutablePinInput.value = mutablePinInput.value.clearAll()
            clearPinInput()
        }
        }
    }
    }


+35 −0
Original line number Original line Diff line number Diff line
@@ -185,6 +185,41 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
        }
        }


    @Test
    fun onShown_againAfterSceneChange_resetsPassword() =
        testScope.runTest {
            val currentScene by collectLastValue(sceneInteractor.desiredScene)
            val password by collectLastValue(underTest.password)
            utils.authenticationRepository.setAuthenticationMethod(
                AuthenticationMethodModel.Password
            )
            utils.authenticationRepository.setUnlocked(false)
            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
            underTest.onShown()

            // The user types a password.
            underTest.onPasswordInputChanged("password")
            assertThat(password).isEqualTo("password")

            // The user doesn't confirm the password, but navigates back to the lockscreen instead.
            sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen), "reason")
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))

            // The user navigates to the bouncer again.
            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))

            underTest.onShown()

            // Ensure the previously-entered password is not shown.
            assertThat(password).isEmpty()
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
        }

    companion object {
    companion object {
        private const val ENTER_YOUR_PASSWORD = "Enter your password"
        private const val ENTER_YOUR_PASSWORD = "Enter your password"
        private const val WRONG_PASSWORD = "Wrong password"
        private const val WRONG_PASSWORD = "Wrong password"
+36 −0
Original line number Original line Diff line number Diff line
@@ -313,6 +313,42 @@ class PinBouncerViewModelTest : SysuiTestCase() {
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
        }
        }


    @Test
    fun onShown_againAfterSceneChange_resetsPin() =
        testScope.runTest {
            val currentScene by collectLastValue(sceneInteractor.desiredScene)
            val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
            utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
            utils.authenticationRepository.setUnlocked(false)
            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")

            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
            underTest.onShown()

            // The user types a PIN.
            FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
                underTest.onPinButtonClicked(digit)
            }
            assertThat(pin).isNotEmpty()

            // The user doesn't confirm the PIN, but navigates back to the lockscreen instead.
            sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen), "reason")
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))

            // The user navigates to the bouncer again.
            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))

            underTest.onShown()

            // Ensure the previously-entered PIN is not shown.
            assertThat(pin).isEmpty()
            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
        }

    @Test
    @Test
    fun backspaceButtonAppearance_withoutAutoConfirm_alwaysShown() =
    fun backspaceButtonAppearance_withoutAutoConfirm_alwaysShown() =
        testScope.runTest {
        testScope.runTest {