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

Commit eff11167 authored by Chandru S's avatar Chandru S Committed by Android (Google) Code Review
Browse files

Merge "Set the default state of canFaceAuth run to false." into main

parents 0e42a651 ab25d937
Loading
Loading
Loading
Loading
+42 −31
Original line number Diff line number Diff line
@@ -20,7 +20,10 @@ package com.android.systemui.biometrics.data.repository
import android.hardware.face.FaceManager
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback
import android.util.Log
import com.android.systemui.biometrics.shared.model.LockoutMode
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.biometrics.shared.model.toLockoutMode
import com.android.systemui.biometrics.shared.model.toSensorStrength
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
@@ -29,16 +32,18 @@ import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn

/** A repository for the global state of Face sensor. */
interface FacePropertyRepository {
    /** Face sensor information, null if it is not available. */
    val sensorInfo: Flow<FaceSensorInfo?>
    val sensorInfo: StateFlow<FaceSensorInfo?>

    /** Get the current lockout mode for the user. This makes a binder based service call. */
    suspend fun getLockoutMode(userId: Int): LockoutMode
}

/** Describes a biometric sensor */
@@ -49,33 +54,39 @@ private const val TAG = "FaceSensorPropertyRepositoryImpl"
@SysUISingleton
class FacePropertyRepositoryImpl
@Inject
constructor(@Application private val applicationScope: CoroutineScope, faceManager: FaceManager?) :
    FacePropertyRepository {
constructor(
    @Application private val applicationScope: CoroutineScope,
    private val faceManager: FaceManager?
) : FacePropertyRepository {

    private val sensorProps: Flow<List<FaceSensorPropertiesInternal>> =
        faceManager?.let {
    override val sensorInfo: StateFlow<FaceSensorInfo?> =
        ConflatedCallbackFlow.conflatedCallbackFlow {
                val callback =
                    object : IFaceAuthenticatorsRegisteredCallback.Stub() {
                        override fun onAllAuthenticatorsRegistered(
                                sensors: List<FaceSensorPropertiesInternal>
                            sensors: List<FaceSensorPropertiesInternal>,
                        ) {
                            if (sensors.isEmpty()) return
                            trySendWithFailureLogging(
                                    sensors,
                                FaceSensorInfo(
                                    sensors.first().sensorId,
                                    sensors.first().sensorStrength.toSensorStrength()
                                ),
                                TAG,
                                "onAllAuthenticatorsRegistered"
                            )
                        }
                    }
                    it.addAuthenticatorsRegisteredCallback(callback)
                faceManager?.addAuthenticatorsRegisteredCallback(callback)
                awaitClose {}
            }
                .shareIn(applicationScope, SharingStarted.Eagerly)
        }
            ?: flowOf(emptyList())
            .onEach { Log.d(TAG, "sensorProps changed: $it") }
            .stateIn(applicationScope, SharingStarted.Eagerly, null)

    override val sensorInfo: Flow<FaceSensorInfo?> =
        sensorProps
            .map { it.firstOrNull() }
            .map { it?.let { FaceSensorInfo(it.sensorId, it.sensorStrength.toSensorStrength()) } }
    override suspend fun getLockoutMode(userId: Int): LockoutMode {
        if (sensorInfo.value == null || faceManager == null) {
            return LockoutMode.NONE
        }
        return faceManager.getLockoutModeForUser(sensorInfo.value!!.id, userId).toLockoutMode()
    }
}
+35 −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.biometrics.shared.model

import android.hardware.biometrics.BiometricConstants

/** Lockout mode. Represents [BiometricConstants.LockoutMode]. */
enum class LockoutMode {
    NONE,
    TIMED,
    PERMANENT,
}

/** Convert [this] to corresponding [LockoutMode] */
fun Int.toLockoutMode(): LockoutMode =
    when (this) {
        BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT -> LockoutMode.PERMANENT
        BiometricConstants.BIOMETRIC_LOCKOUT_TIMED -> LockoutMode.TIMED
        else -> LockoutMode.NONE
    }
+8 −2
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import com.android.systemui.log.SessionTracker
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
import java.io.PrintWriter
import java.util.Arrays
@@ -71,6 +72,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -200,7 +202,7 @@ constructor(
    private val keyguardSessionId: InstanceId?
        get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)

    private val _canRunFaceAuth = MutableStateFlow(true)
    private val _canRunFaceAuth = MutableStateFlow(false)
    override val canRunFaceAuth: StateFlow<Boolean>
        get() = _canRunFaceAuth

@@ -281,7 +283,9 @@ constructor(
                } else {
                    keyguardRepository.isKeyguardGoingAway
                },
                userRepository.userSwitchingInProgress,
                userRepository.selectedUser.map {
                    it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS
                },
            )
            .onEach { anyOfThemIsTrue ->
                if (anyOfThemIsTrue) {
@@ -325,6 +329,7 @@ constructor(
                    cancelDetection()
                }
            }
            .flowOn(mainDispatcher)
            .logDiffsForTable(faceDetectLog, "", "canFaceDetectRun", false)
            .launchIn(applicationScope)
    }
@@ -410,6 +415,7 @@ constructor(
                    cancel()
                }
            }
            .flowOn(mainDispatcher)
            .logDiffsForTable(faceAuthLog, "", "canFaceAuthRun", false)
            .launchIn(applicationScope)
    }
+19 −5
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import com.android.keyguard.FaceAuthUiEvent
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.CoreStartable
import com.android.systemui.R
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
import com.android.systemui.biometrics.shared.model.LockoutMode
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
@@ -35,6 +37,7 @@ import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
@@ -51,6 +54,7 @@ import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield

/**
 * Encapsulates business logic related face authentication being triggered for device entry from
@@ -72,6 +76,7 @@ constructor(
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
    private val userRepository: UserRepository,
    private val facePropertyRepository: FacePropertyRepository,
) : CoreStartable, KeyguardFaceAuthInteractor {

    private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf()
@@ -92,7 +97,7 @@ constructor(
                faceAuthenticationLogger.bouncerVisibilityChanged()
                runFaceAuth(
                    FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN,
                    fallbackToDetect = true
                    fallbackToDetect = false
                )
            }
            .launchIn(applicationScope)
@@ -134,16 +139,25 @@ constructor(

        // User switching should stop face auth and then when it is complete we should trigger face
        // auth so that the switched user can unlock the device with face auth.
        userRepository.userSwitchingInProgress
            .pairwise(false)
            .onEach { (wasSwitching, isSwitching) ->
        userRepository.selectedUser
            .pairwise()
            .onEach { (previous, curr) ->
                val wasSwitching = previous.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS
                val isSwitching = curr.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS
                if (!wasSwitching && isSwitching) {
                    repository.pauseFaceAuth()
                } else if (wasSwitching && !isSwitching) {
                    val lockoutMode = facePropertyRepository.getLockoutMode(curr.userInfo.id)
                    if (lockoutMode == LockoutMode.PERMANENT || lockoutMode == LockoutMode.TIMED) {
                        repository.lockoutFaceAuth()
                    }
                    repository.resumeFaceAuth()
                    yield()
                    runFaceAuth(
                        FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING,
                        fallbackToDetect = true
                        // Fallback to detection if bouncer is not showing so that we can detect a
                        // face and then show the bouncer to the user if face auth can't run
                        fallbackToDetect = !primaryBouncerInteractor.isBouncerShowing()
                    )
                }
            }
+0 −37
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.settings.UserTracker
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
@@ -49,7 +48,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@@ -77,9 +75,6 @@ interface UserRepository {
    /** [UserInfo] of the currently-selected user. */
    val selectedUserInfo: Flow<UserInfo>

    /** Whether user switching is currently in progress. */
    val userSwitchingInProgress: Flow<Boolean>

    /** User ID of the main user. */
    val mainUserId: Int

@@ -162,10 +157,6 @@ constructor(
    private var _isGuestUserResetting: Boolean = false
    override var isGuestUserResetting: Boolean = _isGuestUserResetting

    private val _isUserSwitchingInProgress = MutableStateFlow(false)
    override val userSwitchingInProgress: Flow<Boolean>
        get() = _isUserSwitchingInProgress

    override val isGuestUserCreationScheduled = AtomicBoolean()

    override val isStatusBarUserChipEnabled: Boolean =
@@ -175,12 +166,6 @@ constructor(

    override var isRefreshUsersPaused: Boolean = false

    init {
        if (featureFlags.isEnabled(FACE_AUTH_REFACTOR)) {
            observeUserSwitching()
        }
    }

    override val selectedUser: StateFlow<SelectedUserModel> = run {
        // Some callbacks don't modify the selection status, so maintain the current value.
        var currentSelectionStatus = SelectionStatus.SELECTION_COMPLETE
@@ -259,28 +244,6 @@ constructor(
        return _userSwitcherSettings.value.isUserSwitcherEnabled
    }

    private fun observeUserSwitching() {
        conflatedCallbackFlow {
                val callback =
                    object : UserTracker.Callback {
                        override fun onUserChanging(newUser: Int, userContext: Context) {
                            trySendWithFailureLogging(true, TAG, "userSwitching started")
                        }

                        override fun onUserChanged(newUserId: Int, userContext: Context) {
                            trySendWithFailureLogging(false, TAG, "userSwitching completed")
                        }
                    }
                tracker.addCallback(callback, mainDispatcher.asExecutor())
                trySendWithFailureLogging(false, TAG, "initial value defaulting to false")
                awaitClose { tracker.removeCallback(callback) }
            }
            .onEach { _isUserSwitchingInProgress.value = it }
            // TODO (b/262838215), Make this stateIn and initialize directly in field declaration
            //  once the flag is launched
            .launchIn(applicationScope)
    }

    private suspend fun getSettings(): UserSwitcherSettingsModel {
        return withContext(backgroundDispatcher) {
            val isSimpleUserSwitcher =
Loading