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

Commit 5978d49d authored by Chandru S's avatar Chandru S
Browse files

Expose sim bouncer messages as events instead of state.

There is no need to store state in the repository, all the messages are in response to user events
The default message is derived from the already stored state.

The subsequent CLs change the view and viewModel layer to use this SharedFlow.

Bug: 299343534
Flag: ACONFIG com.android.systemui.compose_bouncer DEVELOPMENT
Test: atest SimBouncerInteractorTest
Change-Id: Ic86aebc99594d6ed3c2779b0a8e862764c3220f0
parent edfcbdb1
Loading
Loading
Loading
Loading
+34 −18
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -201,6 +202,7 @@ class SimBouncerInteractorTest : SysuiTestCase() {
    @Test
    fun verifySimPin() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)
            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(false)
            whenever(telephonyManager.createForSubscriptionId(anyInt()))
@@ -208,8 +210,7 @@ class SimBouncerInteractorTest : SysuiTestCase() {
            whenever(telephonyManager.supplyIccLockPin(anyString()))
                .thenReturn(PinResult(PinResult.PIN_RESULT_TYPE_SUCCESS, 1))

            val msg: String? = underTest.verifySim(listOf(0, 0, 0, 0))
            runCurrent()
            verifySim(listOf(0, 0, 0, 0))
            assertThat(msg).isNull()

            verify(keyguardUpdateMonitor).reportSimUnlocked(1)
@@ -218,6 +219,7 @@ class SimBouncerInteractorTest : SysuiTestCase() {
    @Test
    fun verifySimPin_incorrect_oneRemainingAttempt() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)
            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(false)
            whenever(telephonyManager.createForSubscriptionId(anyInt()))
@@ -229,9 +231,7 @@ class SimBouncerInteractorTest : SysuiTestCase() {
                        1,
                    )
                )

            val msg: String? = underTest.verifySim(listOf(0, 0, 0, 0))
            runCurrent()
            verifySim(listOf(0, 0, 0, 0))

            assertThat(msg).isNull()
            val errorDialogMessage by collectLastValue(bouncerSimRepository.errorDialogMessage)
@@ -245,6 +245,7 @@ class SimBouncerInteractorTest : SysuiTestCase() {
    @Test
    fun verifySimPin_incorrect_threeRemainingAttempts() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)
            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(false)
            whenever(telephonyManager.createForSubscriptionId(anyInt()))
@@ -257,8 +258,7 @@ class SimBouncerInteractorTest : SysuiTestCase() {
                    )
                )

            val msg = underTest.verifySim(listOf(0, 0, 0, 0))
            runCurrent()
            verifySim(listOf(0, 0, 0, 0))

            assertThat(msg).isEqualTo("Enter SIM PIN. You have 3 remaining attempts.")
        }
@@ -266,10 +266,11 @@ class SimBouncerInteractorTest : SysuiTestCase() {
    @Test
    fun verifySimPin_notCorrectLength_tooShort() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)
            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(false)

            val msg = underTest.verifySim(listOf(0))
            verifySim(listOf(0))

            assertThat(msg).isEqualTo(resources.getString(R.string.kg_invalid_sim_pin_hint))
        }
@@ -277,10 +278,12 @@ class SimBouncerInteractorTest : SysuiTestCase() {
    @Test
    fun verifySimPin_notCorrectLength_tooLong() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)

            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(false)

            val msg = underTest.verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))
            verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))

            assertThat(msg).isEqualTo(resources.getString(R.string.kg_invalid_sim_pin_hint))
        }
@@ -288,6 +291,7 @@ class SimBouncerInteractorTest : SysuiTestCase() {
    @Test
    fun verifySimPuk() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)
            whenever(telephonyManager.createForSubscriptionId(anyInt()))
                .thenReturn(telephonyManager)
            whenever(telephonyManager.supplyIccLockPuk(anyString(), anyString()))
@@ -295,13 +299,13 @@ class SimBouncerInteractorTest : SysuiTestCase() {
            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(true)

            var msg = underTest.verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))
            verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))
            assertThat(msg).isEqualTo(resources.getString(R.string.kg_puk_enter_pin_hint))

            msg = underTest.verifySim(listOf(0, 0, 0, 0))
            verifySim(listOf(0, 0, 0, 0))
            assertThat(msg).isEqualTo(resources.getString(R.string.kg_enter_confirm_pin_hint))

            msg = underTest.verifySim(listOf(0, 0, 0, 0))
            verifySim(listOf(0, 0, 0, 0))
            assertThat(msg).isNull()

            runCurrent()
@@ -311,37 +315,49 @@ class SimBouncerInteractorTest : SysuiTestCase() {
    @Test
    fun verifySimPuk_inputTooShort() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)

            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(true)
            val msg = underTest.verifySim(listOf(0, 0, 0, 0))

            verifySim(listOf(0, 0, 0, 0))
            assertThat(msg).isEqualTo(resources.getString(R.string.kg_invalid_sim_puk_hint))
        }

    @Test
    fun verifySimPuk_pinNotCorrectLength() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)
            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(true)

            underTest.verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))
            verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))

            verifySim(listOf(0, 0, 0))

            val msg = underTest.verifySim(listOf(0, 0, 0))
            assertThat(msg).isEqualTo(resources.getString(R.string.kg_invalid_sim_pin_hint))
        }

    @Test
    fun verifySimPuk_confirmedPinDoesNotMatch() =
        testScope.runTest {
            val msg by collectLastValue(underTest.bouncerMessageChanged)

            bouncerSimRepository.setSubscriptionId(1)
            bouncerSimRepository.setSimPukLocked(true)

            underTest.verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))
            underTest.verifySim(listOf(0, 0, 0, 0))
            verifySim(listOf(0, 0, 0, 0, 0, 0, 0, 0, 0))
            verifySim(listOf(0, 0, 0, 0))

            val msg = underTest.verifySim(listOf(0, 0, 0, 1))
            verifySim(listOf(0, 0, 0, 1))
            assertThat(msg).isEqualTo(resources.getString(R.string.kg_puk_enter_pin_hint))
        }

    private suspend fun TestScope.verifySim(pinDigits: List<Int>) {
        runCurrent()
        underTest.verifySim(pinDigits)
    }

    @Test
    fun onErrorDialogDismissed_clearsErrorDialogMessageInRepository() {
        bouncerSimRepository.setSimVerificationErrorMessage("abc")
+47 −41
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -70,6 +72,9 @@ constructor(
    val isLockedEsim: StateFlow<Boolean?> = repository.isLockedEsim
    val errorDialogMessage: StateFlow<String?> = repository.errorDialogMessage

    private val _bouncerMessageChanged = MutableSharedFlow<String?>()
    val bouncerMessageChanged: SharedFlow<String?> = _bouncerMessageChanged

    /** Returns the default message for the sim pin screen. */
    fun getDefaultMessage(): String {
        val isEsimLocked = repository.isLockedEsim.value ?: false
@@ -81,7 +86,7 @@ constructor(
            return ""
        }

        var count = telephonyManager.activeModemCount
        val count = telephonyManager.activeModemCount
        val info: SubscriptionInfo? = repository.activeSubscriptionInfo.value
        val displayName = info?.displayName
        var msg: String =
@@ -156,32 +161,24 @@ constructor(
        repository.setSimVerificationErrorMessage(null)
    }

    /**
     * Based on sim state, unlock the locked sim with the given credentials.
     *
     * @return Any message that should show associated with the provided input. Null means that no
     *   message needs to be shown.
     */
    suspend fun verifySim(input: List<Any>): String? {
    /** Based on sim state, unlock the locked sim with the given credentials. */
    suspend fun verifySim(input: List<Any>) {
        val code = input.joinToString(separator = "")
        if (repository.isSimPukLocked.value) {
            return verifySimPuk(input.joinToString(separator = ""))
            verifySimPuk(code)
        } else {
            verifySimPin(code)
        }

        return verifySimPin(input.joinToString(separator = ""))
    }

    /**
     * Verifies the input and unlocks the locked sim with a 4-8 digit pin code.
     *
     * @return Any message that should show associated with the provided input. Null means that no
     *   message needs to be shown.
     */
    private suspend fun verifySimPin(input: String): String? {
    /** Verifies the input and unlocks the locked sim with a 4-8 digit pin code. */
    private suspend fun verifySimPin(input: String) {
        val subscriptionId = repository.subscriptionId.value
        // A SIM PIN is 4 to 8 decimal digits according to
        // GSM 02.17 version 5.0.1, Section 5.6 PIN Management
        if (input.length < MIN_SIM_PIN_LENGTH || input.length > MAX_SIM_PIN_LENGTH) {
            return resources.getString(R.string.kg_invalid_sim_pin_hint)
            _bouncerMessageChanged.emit(resources.getString(R.string.kg_invalid_sim_pin_hint))
            return
        }
        val result =
            withContext(backgroundDispatcher) {
@@ -190,8 +187,10 @@ constructor(
                telephonyManager.supplyIccLockPin(input)
            }
        when (result.result) {
            PinResult.PIN_RESULT_TYPE_SUCCESS ->
            PinResult.PIN_RESULT_TYPE_SUCCESS -> {
                keyguardUpdateMonitor.reportSimUnlocked(subscriptionId)
                _bouncerMessageChanged.emit(null)
            }
            PinResult.PIN_RESULT_TYPE_INCORRECT -> {
                if (result.attemptsRemaining <= CRITICAL_NUM_OF_ATTEMPTS) {
                    // Show a dialog to display the remaining number of attempts to verify the sim
@@ -199,24 +198,22 @@ constructor(
                    repository.setSimVerificationErrorMessage(
                        getPinPasswordErrorMessage(result.attemptsRemaining)
                    )
                    _bouncerMessageChanged.emit(null)
                } else {
                    return getPinPasswordErrorMessage(result.attemptsRemaining)
                    _bouncerMessageChanged.emit(
                        getPinPasswordErrorMessage(result.attemptsRemaining)
                    )
                }
            }
        }

        return null
    }

    /**
     * Verifies the input and unlocks the locked sim with a puk code instead of pin.
     *
     * This occurs after incorrectly verifying the sim pin multiple times.
     *
     * @return Any message that should show associated with the provided input. Null means that no
     *   message needs to be shown.
     */
    private suspend fun verifySimPuk(entry: String): String? {
    private suspend fun verifySimPuk(entry: String) {
        val (enteredSimPuk, enteredSimPin) = repository.simPukInputModel
        val subscriptionId: Int = repository.subscriptionId.value

@@ -224,10 +221,11 @@ constructor(
        if (enteredSimPuk == null) {
            if (entry.length >= MIN_SIM_PUK_LENGTH) {
                repository.setSimPukUserInput(enteredSimPuk = entry)
                return resources.getString(R.string.kg_puk_enter_pin_hint)
                _bouncerMessageChanged.emit(resources.getString(R.string.kg_puk_enter_pin_hint))
            } else {
                return resources.getString(R.string.kg_invalid_sim_puk_hint)
                _bouncerMessageChanged.emit(resources.getString(R.string.kg_invalid_sim_puk_hint))
            }
            return
        }

        // Stage 2: Set a new sim pin to lock the sim card.
@@ -237,10 +235,11 @@ constructor(
                    enteredSimPuk = enteredSimPuk,
                    enteredSimPin = entry,
                )
                return resources.getString(R.string.kg_enter_confirm_pin_hint)
                _bouncerMessageChanged.emit(resources.getString(R.string.kg_enter_confirm_pin_hint))
            } else {
                return resources.getString(R.string.kg_invalid_sim_pin_hint)
                _bouncerMessageChanged.emit(resources.getString(R.string.kg_invalid_sim_pin_hint))
            }
            return
        }

        // Stage 3: Confirm the newly set sim pin.
@@ -250,7 +249,8 @@ constructor(
                resources.getString(R.string.kg_invalid_confirm_pin_hint)
            )
            repository.setSimPukUserInput(enteredSimPuk = enteredSimPuk)
            return resources.getString(R.string.kg_puk_enter_pin_hint)
            _bouncerMessageChanged.emit(resources.getString(R.string.kg_puk_enter_pin_hint))
            return
        }

        val result =
@@ -261,9 +261,11 @@ constructor(
        resetSimPukUserInput()

        when (result.result) {
            PinResult.PIN_RESULT_TYPE_SUCCESS ->
            PinResult.PIN_RESULT_TYPE_SUCCESS -> {
                keyguardUpdateMonitor.reportSimUnlocked(subscriptionId)
            PinResult.PIN_RESULT_TYPE_INCORRECT ->
                _bouncerMessageChanged.emit(null)
            }
            PinResult.PIN_RESULT_TYPE_INCORRECT -> {
                if (result.attemptsRemaining <= CRITICAL_NUM_OF_ATTEMPTS) {
                    // Show a dialog to display the remaining number of attempts to verify the sim
                    // puk to the user.
@@ -274,17 +276,21 @@ constructor(
                            isEsimLocked = repository.isLockedEsim.value == true
                        )
                    )
                    _bouncerMessageChanged.emit(null)
                } else {
                    return getPukPasswordErrorMessage(
                    _bouncerMessageChanged.emit(
                        getPukPasswordErrorMessage(
                            result.attemptsRemaining,
                            isDefault = false,
                            isEsimLocked = repository.isLockedEsim.value == true
                        )
                    )
                }
            }
            else -> {
                _bouncerMessageChanged.emit(resources.getString(R.string.kg_password_puk_failed))
            }
            else -> return resources.getString(R.string.kg_password_puk_failed)
        }

        return null
    }

    private fun getPinPasswordErrorMessage(attemptsRemaining: Int): String {
+1 −2
Original line number Diff line number Diff line
@@ -157,8 +157,7 @@ class PinBouncerViewModel(
        if (authenticationMethod == AuthenticationMethodModel.Sim) {
            viewModelScope.launch {
                isSimUnlockingDialogVisible.value = true
                val msg = simBouncerInteractor.verifySim(getInput())
                interactor.setMessage(msg)
                simBouncerInteractor.verifySim(getInput())
                isSimUnlockingDialogVisible.value = false
                clearInput()
            }