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

Commit f126ffea authored by Chandru S's avatar Chandru S
Browse files

Support swiping up on lockscreen to enter the device user is either trusted by...

Support swiping up on lockscreen to enter the device user is either trusted by a trust agent or has authenticated with face auth with bypass disabled

Also fixes the issue where swiping up to dismiss shade with an unlocked (by face) lockscreen will trigger SHADE -> GONE transition instead of SHADE -> LOCKSCREEN

Fixes: 295366149
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Test: atest DeviceEntryInteractorTest
Change-Id: Ic99d48591a61f6bb3310f9cb8a7c28ecfca9a6c4
parent cf6dcb6f
Loading
Loading
Loading
Loading
+37 −5
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
@@ -5,6 +21,8 @@ import com.android.systemui.authentication.domain.model.AuthenticationMethodMode
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import javax.inject.Inject
@@ -14,6 +32,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.stateIn

/**
@@ -27,9 +46,11 @@ class DeviceEntryInteractor
@Inject
constructor(
    @Application private val applicationScope: CoroutineScope,
    private val repository: DeviceEntryRepository,
    repository: DeviceEntryRepository,
    private val authenticationInteractor: AuthenticationInteractor,
    sceneInteractor: SceneInteractor,
    deviceEntryFaceAuthRepository: DeviceEntryFaceAuthRepository,
    trustRepository: TrustRepository,
) {
    /**
     * Whether the device is unlocked.
@@ -73,6 +94,13 @@ constructor(
                initialValue = false,
            )

    // Authenticated by a TrustAgent like trusted device, location, etc or by face auth.
    private val passivelyAuthenticated =
        merge(
            trustRepository.isCurrentUserTrusted,
            deviceEntryFaceAuthRepository.isAuthenticated,
        )

    /**
     * Whether it's currently possible to swipe up to enter the device without requiring
     * authentication. This returns `false` whenever the lockscreen has been dismissed.
@@ -81,10 +109,14 @@ constructor(
     * UI.
     */
    val canSwipeToEnter =
        combine(authenticationInteractor.authenticationMethod, isDeviceEntered) {
                authenticationMethod,
                isDeviceEntered ->
                authenticationMethod is AuthenticationMethodModel.Swipe && !isDeviceEntered
        combine(
                authenticationInteractor.authenticationMethod.map {
                    it == AuthenticationMethodModel.Swipe
                },
                passivelyAuthenticated,
                isDeviceEntered
            ) { isSwipeAuthMethod, passivelyAuthenticated, isDeviceEntered ->
                (isSwipeAuthMethod || passivelyAuthenticated) && !isDeviceEntered
            }
            .stateIn(
                scope = applicationScope,
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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
@@ -6,6 +22,8 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -24,6 +42,8 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
    private val utils = SceneTestUtils(this)
    private val testScope = utils.testScope
    private val repository: FakeDeviceEntryRepository = utils.deviceEntryRepository
    private val faceAuthRepository = FakeDeviceEntryFaceAuthRepository()
    private val trustRepository = FakeTrustRepository()
    private val sceneInteractor = utils.sceneInteractor()
    private val authenticationInteractor = utils.authenticationInteractor()
    private val underTest =
@@ -31,6 +51,8 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
            repository = repository,
            authenticationInteractor = authenticationInteractor,
            sceneInteractor = sceneInteractor,
            faceAuthRepository = faceAuthRepository,
            trustRepository = trustRepository,
        )

    @Test
@@ -170,6 +192,40 @@ class DeviceEntryInteractorTest : SysuiTestCase() {
            assertThat(canSwipeToEnter).isFalse()
        }

    @Test
    fun canSwipeToEnter_whenTrustedByTrustManager_isTrue() =
        testScope.runTest {
            val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
            utils.authenticationRepository.setAuthenticationMethod(
                AuthenticationMethodModel.Password
            )
            switchToScene(SceneKey.Lockscreen)
            assertThat(canSwipeToEnter).isFalse()

            trustRepository.setCurrentUserTrusted(true)
            runCurrent()
            faceAuthRepository.isAuthenticated.value = false

            assertThat(canSwipeToEnter).isTrue()
        }

    @Test
    fun canSwipeToEnter_whenAuthenticatedByFace_isTrue() =
        testScope.runTest {
            val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
            utils.authenticationRepository.setAuthenticationMethod(
                AuthenticationMethodModel.Password
            )
            switchToScene(SceneKey.Lockscreen)
            assertThat(canSwipeToEnter).isFalse()

            faceAuthRepository.isAuthenticated.value = true
            runCurrent()
            trustRepository.setCurrentUserTrusted(false)

            assertThat(canSwipeToEnter).isTrue()
        }

    @Test
    fun isAuthenticationRequired_lockedAndSecured_true() =
        testScope.runTest {
+11 −1
Original line number Diff line number Diff line
@@ -16,6 +16,16 @@
package com.android.systemui.deviceentry.data

import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeTrustRepositoryModule
import dagger.Module

@Module(includes = [FakeDeviceEntryRepositoryModule::class]) object FakeDeviceEntryDataLayerModule
@Module(
    includes =
        [
            FakeDeviceEntryRepositoryModule::class,
            FakeTrustRepositoryModule::class,
            FakeDeviceEntryFaceAuthRepositoryModule::class,
        ]
)
object FakeDeviceEntryDataLayerModule
+0 −2
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.data

import com.android.systemui.keyguard.data.repository.FakeCommandQueueModule
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepositoryModule
import dagger.Module
@@ -25,7 +24,6 @@ import dagger.Module
    includes =
        [
            FakeCommandQueueModule::class,
            FakeDeviceEntryFaceAuthRepositoryModule::class,
            FakeKeyguardRepositoryModule::class,
            FakeKeyguardTransitionRepositoryModule::class,
        ]
+11 −1
Original line number Diff line number Diff line
@@ -18,13 +18,18 @@
package com.android.systemui.keyguard.data.repository

import com.android.keyguard.TrustGrantFlags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.TrustModel
import dagger.Binds
import dagger.Module
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

class FakeTrustRepository : TrustRepository {
@SysUISingleton
class FakeTrustRepository @Inject constructor() : TrustRepository {
    private val _isTrustUsuallyManaged = MutableStateFlow(false)
    override val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean>
        get() = _isTrustUsuallyManaged
@@ -63,3 +68,8 @@ class FakeTrustRepository : TrustRepository {
        _isTrustUsuallyManaged.value = value
    }
}

@Module
interface FakeTrustRepositoryModule {
    @Binds fun bindFake(fake: FakeTrustRepository): TrustRepository
}
Loading