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

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

Merge "Add gating conditions for active unlock" into main

parents e36b59a8 a47949e7
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.systemui.bouncer.shared.logging.BouncerUiEvent
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.deviceentry.domain.interactor.canTriggerActiveUnlock
import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
@@ -42,7 +43,6 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.fakeTrustRepository
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.data.repository.fakePowerRepository
@@ -123,12 +123,16 @@ class BouncerInteractorTest : SysuiTestCase() {
    @Test
    fun isCurrentUserActiveUnlockRunning_passiveAuthMaySucceedBeforeFullyShowingBouncer_true() =
        kosmos.runTest {
            // We need lazy<BouncerInteractor> to be initialized so that ActiveUnlockInteractor
            // is also initialized and eagerly updates canRunActiveUnlock
            underTest.let {
                kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                    AuthenticationMethodModel.Pin
                )
            kosmos.fakeTrustRepository.setCurrentUserActiveUnlockAvailable(true)
                kosmos.canTriggerActiveUnlock(canRun = true)
                assertThat(underTest.passiveAuthMaySucceedBeforeFullyShowingBouncer()).isTrue()
            }
        }

    @Test
    fun pinAuthMethod_sim_skipsAuthentication() =
+114 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.deviceentry.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.fakeTrustRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@ExperimentalCoroutinesApi
@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableSceneContainer
class ActiveUnlockInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private lateinit var underTest: ActiveUnlockInteractor

    @Before
    fun setUp() {
        underTest = kosmos.activeUnlockInteractor
        kosmos.canTriggerActiveUnlock(canRun = true)
    }

    @Test
    fun canTriggerActiveUnlockTrue() =
        testScope.runTest {
            val canRunActiveUnlock by collectLastValue(underTest.canRunActiveUnlock)

            // using initial state from setUp
            assertThat(canRunActiveUnlock).isTrue()
        }

    @Test
    fun currentUserActiveUnlockNotRunning_canTriggerActiveUnlockFalse() =
        testScope.runTest {
            val canRunActiveUnlock by collectLastValue(underTest.canRunActiveUnlock)
            kosmos.fakeTrustRepository.setCurrentUserActiveUnlockAvailable(false)
            runCurrent()

            assertThat(canRunActiveUnlock).isFalse()
        }

    @Test
    fun fingerprintLockedOut_canTriggerActiveUnlockFalse() =
        testScope.runTest {
            val canRunActiveUnlock by collectLastValue(underTest.canRunActiveUnlock)
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
            runCurrent()

            assertThat(canRunActiveUnlock).isFalse()
        }

    @Test
    fun fingerprintNotCurrentlyAllowed_canTriggerActiveUnlockFalse() =
        testScope.runTest {
            val canRunActiveUnlock by collectLastValue(underTest.canRunActiveUnlock)
            kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
            runCurrent()

            assertThat(canRunActiveUnlock).isFalse()
        }

    @Test
    fun userSwitching_canTriggerActiveUnlockFalse() =
        testScope.runTest {
            val canRunActiveUnlock by collectLastValue(underTest.canRunActiveUnlock)
            kosmos.fakeUserRepository.setMainUserIsUserSwitching()
            runCurrent()

            assertThat(canRunActiveUnlock).isFalse()
        }

    @Test
    fun isUnlocked_canTriggerActiveUnlockFalse() =
        testScope.runTest {
            val canRunActiveUnlock by collectLastValue(underTest.canRunActiveUnlock)
            kosmos.fakeDeviceEntryRepository.deviceUnlockStatus.value =
                DeviceUnlockStatus(isUnlocked = true, deviceUnlockSource = null)
            runCurrent()

            assertThat(canRunActiveUnlock).isFalse()
        }
}
+19 −12
Original line number Diff line number Diff line
@@ -42,14 +42,27 @@ class DeviceEntryBiometricsAllowedInteractorTest : SysuiTestCase() {
    private val underTest = kosmos.deviceEntryBiometricsAllowedInteractor

    @Test
    fun isFingerprintAuthCurrentlyAllowed_true() =
    fun isFingerprintAuthCurrentlyAllowed_initialFalse() =
        testScope.runTest {
            val fpAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
            assertThat(fpAllowed).isFalse()
        }

    @Test
    fun isFingerprintAuthCurrentlyAllowed_initialStateTrue() =
        testScope.runTest {
            kosmos.allowFingerprint()
            val fpAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
            assertThat(fpAllowed).isTrue()
        }

    @Test
    fun isFingerprintAuthCurrentlyAllowed_becomesTrue() =
        testScope.runTest {
            val fpAllowed by collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)

            // WHEN: not locked out, no face sensor, no strong auth requirements
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
            kosmos.fakeFacePropertyRepository.setSensorInfo(null)
            kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
            kosmos.allowFingerprint()

            // THEN fp is allowed
            assertThat(fpAllowed).isTrue()
@@ -63,10 +76,7 @@ class DeviceEntryBiometricsAllowedInteractorTest : SysuiTestCase() {
            // WHEN: not locked out, face is strong & locked out,  no strong auth requirements
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
            kosmos.fakeFacePropertyRepository.setSensorInfo(
                FaceSensorInfo(
                    id = 0,
                    strength = SensorStrength.STRONG,
                )
                FaceSensorInfo(id = 0, strength = SensorStrength.STRONG)
            )
            kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
            kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
@@ -83,10 +93,7 @@ class DeviceEntryBiometricsAllowedInteractorTest : SysuiTestCase() {
            // WHEN: not locked out, face is convenience & locked out, no strong auth requirements
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
            kosmos.fakeFacePropertyRepository.setSensorInfo(
                FaceSensorInfo(
                    id = 0,
                    strength = SensorStrength.CONVENIENCE,
                )
                FaceSensorInfo(id = 0, strength = SensorStrength.CONVENIENCE)
            )
            kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
            kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+2 −2
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ class TrustRepositoryTest : SysuiTestCase() {
            runCurrent()
            verify(trustManager).registerTrustListener(listener.capture())
            val isCurrentUserActiveUnlockRunning by
                collectLastValue(underTest.isCurrentUserActiveUnlockRunning)
                collectLastValue(underTest.isCurrentUserActiveUnlockEnabled)
            userRepository.setSelectedUserInfo(users[1])

            // active unlock running = true for users[0].id, but not the current user
@@ -254,7 +254,7 @@ class TrustRepositoryTest : SysuiTestCase() {
            runCurrent()
            verify(trustManager).registerTrustListener(listener.capture())
            val isCurrentUserActiveUnlockRunning by
                collectLastValue(underTest.isCurrentUserActiveUnlockRunning)
                collectLastValue(underTest.isCurrentUserActiveUnlockEnabled)
            userRepository.setSelectedUserInfo(users[0])

            listener.value.onIsActiveUnlockRunningChanged(true, users[0].id)
+3 −5
Original line number Diff line number Diff line
@@ -36,8 +36,8 @@ import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.ActiveUnlockInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.keyguard.domain.interactor.TrustInteractor
import com.android.systemui.log.SessionTracker
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
@@ -75,7 +75,7 @@ constructor(
    private val sessionTracker: SessionTracker,
    sceneInteractor: SceneInteractor,
    sceneBackInteractor: SceneBackInteractor,
    private val trustInteractor: TrustInteractor,
    private val activeUnlockInteractor: ActiveUnlockInteractor,
    @ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
) {
    private val _onIncorrectBouncerInput = MutableSharedFlow<Unit>()
@@ -190,11 +190,9 @@ constructor(
     * pin/pattern/password. Else, false.
     */
    suspend fun passiveAuthMaySucceedBeforeFullyShowingBouncer(): Boolean {
        // TODO (b/411414026): Check KUM#canTriggerActiveUnlockBasedOnDeviceState to determine
        // whether active unlock can run now
        return authenticationInteractor.getAuthenticationMethod() != Sim &&
            (deviceEntryFaceAuthInteractor.canFaceAuthRun() ||
                trustInteractor.isCurrentUserActiveUnlockRunning())
                activeUnlockInteractor.canRunActiveUnlock.value)
    }

    /** Notifies that the user has places down a pointer, not necessarily dragging just yet. */
Loading