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

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

Merge changes If61ac8f0,I3a20f400 into main

* changes:
  [flexiglass] Hydrates biometrics displayState with proper state
  [flexiglass] Report userPresent when device entered.
parents 850a834c 70ec7531
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -617,6 +617,33 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
                .isEqualTo(DeviceEntryRestrictionReason.DeviceNotUnlockedSinceMainlineUpdate)
        }

    @Test
    fun reportUserPresent_whenDeviceEntered() =
        testScope.runTest {
            val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
            assertThat(isDeviceEntered).isFalse()
            assertThat(kosmos.fakeDeviceEntryRepository.userPresentCount).isEqualTo(0)

            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                SuccessFingerprintAuthenticationStatus(0, true)
            )
            runCurrent()
            switchToScene(Scenes.Gone)
            assertThat(isDeviceEntered).isTrue()
            assertThat(kosmos.fakeDeviceEntryRepository.userPresentCount).isEqualTo(1)

            switchToScene(Scenes.Lockscreen)
            assertThat(isDeviceEntered).isFalse()
            assertThat(kosmos.fakeDeviceEntryRepository.userPresentCount).isEqualTo(1)

            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                SuccessFingerprintAuthenticationStatus(0, true)
            )
            switchToScene(Scenes.Gone)
            assertThat(isDeviceEntered).isTrue()
            assertThat(kosmos.fakeDeviceEntryRepository.userPresentCount).isEqualTo(2)
        }

    private fun TestScope.verifyRestrictionReasonsForAuthFlags(
        vararg authFlagToDeviceEntryRestriction: Pair<Int, DeviceEntryRestrictionReason?>
    ) {
+49 −12
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

@file:OptIn(ExperimentalCoroutinesApi::class)

package com.android.systemui.biometrics.domain.interactor

import android.hardware.biometrics.AuthenticateOptions
@@ -21,16 +23,22 @@ import android.hardware.biometrics.IBiometricContextListener
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
@@ -76,20 +84,34 @@ constructor(
    deviceStateRepository: DeviceStateRepository,
    keyguardTransitionInteractor: KeyguardTransitionInteractor,
    udfpsOverlayInteractor: UdfpsOverlayInteractor,
    deviceEntryInteractor: Lazy<DeviceEntryInteractor>,
) : LogContextInteractor {

    override val displayState =
        keyguardTransitionInteractor.startedKeyguardTransitionStep.map {
            when (it.to) {
                KeyguardState.LOCKSCREEN,
                KeyguardState.OCCLUDED,
                KeyguardState.ALTERNATE_BOUNCER,
                KeyguardState.PRIMARY_BOUNCER -> AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN
                KeyguardState.AOD -> AuthenticateOptions.DISPLAY_STATE_AOD
                KeyguardState.OFF,
                KeyguardState.DOZING -> AuthenticateOptions.DISPLAY_STATE_NO_UI
                KeyguardState.DREAMING -> AuthenticateOptions.DISPLAY_STATE_SCREENSAVER
                else -> AuthenticateOptions.DISPLAY_STATE_UNKNOWN
    override val displayState: Flow<Int> by lazy {
        if (SceneContainerFlag.isEnabled) {
            combine(
                deviceEntryInteractor.get().isDeviceEntered,
                keyguardTransitionInteractor.startedKeyguardTransitionStep,
            ) { isDeviceEntered, transitionStep ->
                if (isDeviceEntered) {
                    AuthenticateOptions.DISPLAY_STATE_UNKNOWN
                } else {
                    transitionStep.toAuthenticateOptions(
                        // Here when isDeviceEntered=false which always means that the device is on
                        // top of the keyguard. Therefore, any KeyguardState that doesn't have a
                        // more specific mapping as a sub-state of keyguard, maps to LOCKSCREEN
                        // instead of UNKNOWN, because it _is_ a known display state and that
                        // display state is undeniably LOCKSCREEN.
                        default = AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN
                    )
                }
            }
        } else {
            keyguardTransitionInteractor.startedKeyguardTransitionStep.map { transitionStep ->
                transitionStep.toAuthenticateOptions(
                    default = AuthenticateOptions.DISPLAY_STATE_UNKNOWN
                )
            }
        }
    }

@@ -152,6 +174,21 @@ constructor(
        }
    }

    private fun TransitionStep.toAuthenticateOptions(default: Int): Int {
        return when (this.to) {
            KeyguardState.LOCKSCREEN,
            KeyguardState.OCCLUDED,
            KeyguardState.ALTERNATE_BOUNCER,
            KeyguardState.PRIMARY_BOUNCER -> AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN
            KeyguardState.AOD -> AuthenticateOptions.DISPLAY_STATE_AOD
            KeyguardState.OFF,
            KeyguardState.DOZING -> AuthenticateOptions.DISPLAY_STATE_NO_UI
            KeyguardState.DREAMING -> AuthenticateOptions.DISPLAY_STATE_SCREENSAVER
            KeyguardState.GONE -> AuthenticateOptions.DISPLAY_STATE_UNKNOWN
            else -> default
        }
    }

    companion object {
        private const val TAG = "ContextRepositoryImpl"
    }
+13 −0
Original line number Diff line number Diff line
@@ -39,6 +39,12 @@ interface DeviceEntryRepository {
     * the lockscreen.
     */
    val isBypassEnabled: StateFlow<Boolean>

    /**
     * Reports, to system server, that the user is "present" now. This is a signal that system
     * server uses to know that the device has been entered.
     */
    suspend fun reportUserPresent()
}

/** Encapsulates application state for device entry. */
@@ -79,6 +85,13 @@ constructor(
                initialValue = keyguardBypassController.bypassEnabled,
            )

    override suspend fun reportUserPresent() {
        withContext(backgroundDispatcher) {
            val selectedUserId = userRepository.selectedUser.value.userInfo.id
            lockPatternUtils.userPresent(selectedUserId)
        }
    }

    companion object {
        private const val TAG = "DeviceEntryRepositoryImpl"
    }
+6 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

@@ -108,6 +109,11 @@ constructor(
                    false
                }
            }
            .onEach { isDeviceEntered ->
                if (isDeviceEntered) {
                    repository.reportUserPresent()
                }
            }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.Eagerly,
+63 −5
Original line number Diff line number Diff line
@@ -23,15 +23,22 @@ 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.domain.interactor.deviceEntryInteractor
import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.display.data.repository.fakeDeviceStateRepository
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -61,10 +68,11 @@ class LogContextInteractorImplTest : SysuiTestCase() {
    fun setup() {
        interactor =
            LogContextInteractorImpl(
                testScope.backgroundScope,
                deviceStateRepository,
                kosmos.keyguardTransitionInteractor,
                udfpsOverlayInteractor,
                applicationScope = testScope.backgroundScope,
                deviceStateRepository = deviceStateRepository,
                keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor,
                udfpsOverlayInteractor = udfpsOverlayInteractor,
                deviceEntryInteractor = { kosmos.deviceEntryInteractor },
            )
    }

@@ -135,7 +143,57 @@ class LogContextInteractorImplTest : SysuiTestCase() {
        }

    @Test
    fun displayStateChanges() =
    @EnableSceneContainer
    fun displayStateChanges_withSceneContainer() =
        testScope.runTest {
            val displayState = collectLastValue(interactor.displayState)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.OFF)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_NO_UI)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.DOZING)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_NO_UI)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.DREAMING)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_SCREENSAVER)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_AOD)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.ALTERNATE_BOUNCER)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.LOCKSCREEN)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.OCCLUDED)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN)

            // Unlock the device.
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                SuccessFingerprintAuthenticationStatus(0, true)
            )
            runCurrent()
            kosmos.sceneInteractor.snapToScene(Scenes.Gone, "")

            keyguardTransitionRepository.startTransitionTo(KeyguardState.GONE)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_UNKNOWN)

            keyguardTransitionRepository.startTransitionTo(KeyguardState.UNDEFINED)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_UNKNOWN)

            // Relock the device
            kosmos.sceneInteractor.snapToScene(Scenes.Lockscreen, "")
            keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD)
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_AOD)
        }

    @Test
    @DisableSceneContainer
    fun displayStateChanges_withoutSceneContainer() =
        testScope.runTest {
            val displayState = collectLastValue(interactor.displayState)

Loading