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

Commit 020d16a9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "SL composable/viewmodel cleanup" into main

parents cd30d43a 694e6fd6
Loading
Loading
Loading
Loading
+121 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR
import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.platform.test.annotations.EnableFlags
import android.security.Flags.FLAG_SECURE_LOCK_DEVICE
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -41,9 +43,11 @@ import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.biometrics.shared.model.toSensorType
import com.android.systemui.biometrics.ui.viewmodel.BiometricAuthIconViewModel.BiometricAuthModalities
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.securelockdevice.ui.viewmodel.SecureLockDeviceBiometricAuthContentViewModel
import com.android.systemui.securelockdevice.ui.viewmodel.secureLockDeviceBiometricAuthContentViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runCurrent
@@ -77,6 +81,7 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
        } else if (sensorType == TYPE_REAR) {
            kosmos.fingerprintPropertyRepository.supportsRearFps(sensorStrength)
        }
        kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
    }

    private fun enrollFace(isStrongBiometric: Boolean) {
@@ -86,6 +91,7 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
                strength = if (isStrongBiometric) SensorStrength.STRONG else SensorStrength.WEAK,
            )
        kosmos.facePropertyRepository.setSensorInfo(faceSensorInfo)
        kosmos.biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
    }

    private fun startBiometricPrompt(hasFpAuth: Boolean, isImplicitFlow: Boolean = false) {
@@ -103,12 +109,22 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
        }
    }

    private fun startSecureLockDevicePrompt() {
        secureLockDeviceViewModel!!.showAuthenticating()
    }

    private fun initPromptViewModel() {
        promptViewModel = kosmos.promptViewModel
        underTest = promptViewModel!!.iconViewModel.internal
        underTest.activateIn(testScope)
    }

    private fun initSecureLockDeviceViewModel() {
        secureLockDeviceViewModel = kosmos.secureLockDeviceBiometricAuthContentViewModel
        underTest = secureLockDeviceViewModel!!.iconViewModel
        underTest.activateIn(testScope)
    }

    @Test
    fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_face() {
        testScope.runTest {
@@ -127,6 +143,21 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
        }
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_face() {
        testScope.runTest {
            initSecureLockDeviceViewModel()
            val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType)

            enrollFace(isStrongBiometric = true)
            runCurrent()
            startSecureLockDevicePrompt()

            assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.Face)
        }
    }

    @Test
    fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_sfps() {
        testScope.runTest {
@@ -147,6 +178,24 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
        }
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_sfps() {
        testScope.runTest {
            initSecureLockDeviceViewModel()
            val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType)

            enrollFingerprint(
                sensorStrength = SensorStrength.STRONG,
                sensorType = TYPE_POWER_BUTTON,
            )
            runCurrent()
            startSecureLockDevicePrompt()

            assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.Sfps)
        }
    }

    @Test
    fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_nonSfps() {
        testScope.runTest {
@@ -168,6 +217,24 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
        }
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_nonSfps() {
        testScope.runTest {
            initSecureLockDeviceViewModel()
            val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType)

            enrollFingerprint(
                sensorStrength = SensorStrength.STRONG,
                sensorType = TYPE_UDFPS_OPTICAL,
            )
            runCurrent()
            startSecureLockDevicePrompt()

            assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.NonSfps)
        }
    }

    @Test
    fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_sfpsCoexImplicit() {
        testScope.runTest {
@@ -212,6 +279,25 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
        }
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_sfpsCoex() {
        testScope.runTest {
            initSecureLockDeviceViewModel()
            val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType)

            enrollFingerprint(
                sensorStrength = SensorStrength.STRONG,
                sensorType = TYPE_POWER_BUTTON,
            )
            enrollFace(isStrongBiometric = true)
            runCurrent()
            startSecureLockDevicePrompt()

            assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.SfpsCoex)
        }
    }

    @Test
    fun activeBiometricAuthType_basedOnModalitiesAndFaceMode_forBiometricPrompt_coexNonSfpsImplicit() {
        testScope.runTest {
@@ -256,6 +342,41 @@ class BiometricAuthIconViewModelTest() : SysuiTestCase() {
        }
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun activeBiometricAuthType_basedOnModalities_forSecureLockDevice_coexNonSfps() {
        testScope.runTest {
            initSecureLockDeviceViewModel()
            val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType)

            enrollFingerprint(
                sensorStrength = SensorStrength.STRONG,
                sensorType = TYPE_UDFPS_OPTICAL,
            )
            enrollFace(isStrongBiometric = true)
            runCurrent()
            startSecureLockDevicePrompt()

            assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.NonSfpsCoex)
        }
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun activeBiometricAuthNone_forNonStrongBiometrics_forSecureLockDevice() {
        testScope.runTest {
            initSecureLockDeviceViewModel()
            val activeBiometricAuthType by collectLastValue(underTest.activeBiometricAuthType)

            enrollFingerprint(sensorStrength = SensorStrength.WEAK, sensorType = TYPE_UDFPS_OPTICAL)
            enrollFace(isStrongBiometric = false)
            runCurrent()
            startSecureLockDevicePrompt()

            assertThat(activeBiometricAuthType).isEqualTo(BiometricAuthModalities.None)
        }
    }

    /** Initialize the prompt according to the test configuration. */
    private fun PromptSelectorInteractor.initializePrompt(
        fingerprint: FingerprintSensorPropertiesInternal? = null,
+78 −4
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.systemui.securelockdevice.domain.interactor.secureLockDeviceI
import com.android.systemui.testKosmos
import com.google.android.msdl.data.model.MSDLToken
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Job
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -50,21 +51,32 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val testScope = kosmos.testScope
    private lateinit var secureLockDeviceInteractor: SecureLockDeviceInteractor
    private lateinit var underTest: SecureLockDeviceBiometricAuthContentViewModel

    @Before
    fun setUp() {
        kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceEnabled()
        kosmos.fakeSecureLockDeviceRepository.onSuccessfulPrimaryAuth()
        secureLockDeviceInteractor = kosmos.secureLockDeviceInteractor
    }

    @Test
    fun onBiometricAuthRequested_showsAuthenticating_() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectLastValue(underTest.isAuthenticating)

            secureLockDeviceInteractor.onBiometricAuthRequested()
            runCurrent()

        underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
        underTest.activateIn(testScope)
            assertThat(isAuthenticating).isTrue()
        }

    @Test
    fun updatesStateAndPlaysHaptics_onFaceFailureOrError() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectValues(underTest.isAuthenticating)
            val isAuthenticated by collectLastValue(underTest.isAuthenticated)
            val showingError by collectValues(underTest.showingError)
@@ -90,6 +102,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
    @Test
    fun updatesStateOnRetryAfterFaceFailureOrError() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectLastValue(underTest.isAuthenticating)
            val isAuthenticated by collectLastValue(underTest.isAuthenticated)
            val showingError by collectLastValue(underTest.showingError)
@@ -115,6 +129,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
    @Test
    fun updatesStateAndSkipsHaptics_onFaceHelp() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectLastValue(underTest.isAuthenticating)
            val isAuthenticated by collectLastValue(underTest.isAuthenticated)
            val showingError by collectLastValue(underTest.showingError)
@@ -133,6 +149,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
    @Test
    fun updatesState_onFaceSuccess_andPlaysHapticsOnConfirm() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectLastValue(underTest.isAuthenticating)
            val isAuthenticated by collectLastValue(underTest.isAuthenticated)
            val showingError by collectLastValue(underTest.showingError)
@@ -161,6 +179,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
    @Test
    fun updatesStateAndPlaysHaptics_onFingerprintFailureOrError() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectValues(underTest.isAuthenticating)
            val isAuthenticated by collectLastValue(underTest.isAuthenticated)
            val showingError by collectValues(underTest.showingError)
@@ -186,6 +206,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
    @Test
    fun updatesStateAndSkipsHaptics_onFingerprintHelp() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectLastValue(underTest.isAuthenticating)
            val isAuthenticated by collectLastValue(underTest.isAuthenticated)
            val showingError by collectLastValue(underTest.showingError)
@@ -204,6 +226,8 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
    @Test
    fun updatesStateAndPlaysHaptics_onFingerprintSuccess() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isAuthenticating by collectLastValue(underTest.isAuthenticating)
            val isAuthenticated by collectLastValue(underTest.isAuthenticated)
            val showingError by collectLastValue(underTest.showingError)
@@ -219,4 +243,54 @@ class SecureLockDeviceBiometricAuthContentViewModelTest : SysuiTestCase() {
            assertThat(isAuthenticated?.isAuthenticatedAndConfirmed).isTrue()
            assertThat(kosmos.fakeMSDLPlayer.latestTokenPlayed).isEqualTo(MSDLToken.UNLOCK)
        }

    @Test
    fun onSuccessfulAuthentication_notifiesInteractorAndHides_uponAnimationFinished() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            underTest.activateIn(this)
            val isReadyToDismiss by
                collectLastValue(secureLockDeviceInteractor.isFullyUnlockedAndReadyToDismiss)

            underTest.startAppearAnimation()
            runCurrent()

            assertThat(underTest.isVisible).isTrue()
            assertThat(isReadyToDismiss).isFalse()

            underTest.showAuthenticated(BiometricModality.Fingerprint)
            runCurrent()

            assertThat(underTest.isAuthenticationComplete).isTrue()
            assertThat(isReadyToDismiss).isFalse()

            underTest.onIconAnimationFinished()
            runCurrent()

            assertThat(isReadyToDismiss).isTrue()
            assertThat(underTest.isVisible).isFalse()
        }

    @Test
    fun onDeactivated_hidesComposable_notifiesInteractor() =
        testScope.runTest {
            val underTest = kosmos.secureLockDeviceBiometricAuthContentViewModel
            val job = Job()
            underTest.activateIn(this, job)
            runCurrent()

            secureLockDeviceInteractor.onBiometricAuthRequested()
            underTest.startAppearAnimation()
            runCurrent()

            assertThat(underTest.isVisible).isTrue()
            assertThat(secureLockDeviceInteractor.isBiometricAuthVisible.value).isTrue()

            job.cancel()
            runCurrent()

            // THEN the viewmodel is no longer visible and the interactor is notified
            assertThat(underTest.isVisible).isFalse()
            assertThat(secureLockDeviceInteractor.isBiometricAuthVisible.value).isFalse()
        }
}
+1 −1
Original line number Diff line number Diff line
@@ -162,11 +162,11 @@ constructor(
            ?: secureLockDeviceViewModel?.isAuthenticated
            ?: emptyFlow()

    /** If the auth is pending confirmation. */
    private val isPendingConfirmation: Flow<Boolean> =
        isAuthenticated.map { authState ->
            authState.isAuthenticated && authState.needsUserConfirmation
        }
    /** If the auth is pending confirmation. */
    val isPendingConfirmationState: Boolean by
        isPendingConfirmation.hydratedStateOf(
            traceName = "isPendingConfirmation",
+2 −2
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ import com.android.systemui.bouncer.shared.model.SecureLockDeviceBouncerActionBu
import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder
import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay
import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel
import com.android.systemui.lifecycle.rememberActivated
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.res.R
import com.android.systemui.securelockdevice.ui.viewmodel.SecureLockDeviceBiometricAuthContentViewModel
import com.android.systemui.util.ui.compose.LottieColorUtils
@@ -88,7 +88,7 @@ fun SecureLockDeviceContent(
    modifier: Modifier = Modifier,
) {
    val secureLockDeviceViewModel =
        rememberActivated(traceName = "SecureLockDeviceBiometricAuthContentViewModel") {
        rememberViewModel(traceName = "SecureLockDeviceBiometricAuthContentViewModel") {
            secureLockDeviceViewModelFactory.create()
        }

+50 −53

File changed.

Preview size limit exceeded, changes collapsed.

Loading