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

Commit 1e022d25 authored by Grace Cheng's avatar Grace Cheng Committed by Android (Google) Code Review
Browse files

Merge "Add rest to unlock progress bar to BiometricPrompt" into main

parents a4ad8c50 2a3ab13f
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package android.hardware.biometrics;

import android.hardware.biometrics.BiometricSourceType;

/**
 * Low-level callback interface between <Biometric>Manager and <Auth>Service. Allows core system
 * services (e.g. SystemUI) to register a listener for updates about the current state of biometric
@@ -49,4 +51,15 @@ oneway interface AuthenticationStateListener {
     * @param userId The user Id for the requested authentication
     */
    void onAuthenticationFailed(int requestReason, int userId);

    /**
     * Defines behavior in response to biometric being acquired.
     * @param biometricSourceType identifies [BiometricSourceType] biometric was acquired for
     * @param requestReason reason from [BiometricRequestConstants.RequestReason] for authentication
     * @param acquiredInfo [BiometricFingerprintConstants.FingerprintAcquired] int corresponding to
     *                     a known acquired message.
     */
    void onAuthenticationAcquired(
        in BiometricSourceType biometricSourceType, int requestReason, int acquiredInfo
    );
}
+5 −0
Original line number Diff line number Diff line
@@ -25,9 +25,11 @@ import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor
import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor
import com.android.systemui.biometrics.fakeFingerprintInteractiveToAuthProvider
import com.android.systemui.biometrics.shared.model.AuthenticationReason
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.coroutines.collectLastValue
@@ -146,6 +148,7 @@ class SideFpsProgressBarViewModelTest : SysuiTestCase() {
            kosmos.fakeKeyguardRepository.setIsDozing(false)
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                AcquiredFingerprintAuthenticationStatus(
                    AuthenticationReason.DeviceEntryAuthentication,
                    BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START
                )
            )
@@ -165,6 +168,7 @@ class SideFpsProgressBarViewModelTest : SysuiTestCase() {
            kosmos.fakeKeyguardRepository.setIsDozing(true)
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                AcquiredFingerprintAuthenticationStatus(
                    AuthenticationReason.DeviceEntryAuthentication,
                    BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START
                )
            )
@@ -177,6 +181,7 @@ class SideFpsProgressBarViewModelTest : SysuiTestCase() {
    private fun createViewModel() =
        SideFpsProgressBarViewModel(
            kosmos.applicationContext,
            kosmos.biometricStatusInteractor,
            kosmos.deviceEntryFingerprintAuthInteractor,
            kosmos.sideFpsSensorInteractor,
            kosmos.dozeServiceHost,
+70 −31
Original line number Diff line number Diff line
@@ -24,17 +24,24 @@ import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
import android.hardware.biometrics.BiometricSourceType
import com.android.systemui.biometrics.shared.model.AuthenticationReason
import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
import com.android.systemui.biometrics.shared.model.AuthenticationState
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus
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.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn

/** A repository for the state of biometric authentication. */
@@ -44,6 +51,9 @@ interface BiometricStatusRepository {
     * [NotRunning].
     */
    val fingerprintAuthenticationReason: Flow<AuthenticationReason>

    /** The current status of an acquired fingerprint. */
    val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus>
}

@SysUISingleton
@@ -54,53 +64,53 @@ constructor(
    private val biometricManager: BiometricManager?
) : BiometricStatusRepository {

    override val fingerprintAuthenticationReason: Flow<AuthenticationReason> =
    private val authenticationState: Flow<AuthenticationState> =
        conflatedCallbackFlow {
                val updateFingerprintAuthenticateReason = { reason: AuthenticationReason ->
                    trySendWithFailureLogging(
                        reason,
                        TAG,
                        "Error sending fingerprintAuthenticateReason reason"
                    )
                val updateAuthenticationState = { state: AuthenticationState ->
                    trySendWithFailureLogging(state, TAG, "Error sending AuthenticationState state")
                }

                val authenticationStateListener =
                    object : AuthenticationStateListener.Stub() {
                        override fun onAuthenticationStarted(requestReason: Int) {
                            val authenticationReason =
                                when (requestReason) {
                                    REASON_AUTH_BP ->
                                        AuthenticationReason.BiometricPromptAuthentication
                                    REASON_AUTH_KEYGUARD ->
                                        AuthenticationReason.DeviceEntryAuthentication
                                    REASON_AUTH_OTHER -> AuthenticationReason.OtherAuthentication
                                    REASON_AUTH_SETTINGS ->
                                        AuthenticationReason.SettingsAuthentication(
                                            SettingsOperations.OTHER
                                        )
                                    REASON_ENROLL_ENROLLING ->
                                        AuthenticationReason.SettingsAuthentication(
                                            SettingsOperations.ENROLL_ENROLLING
                            val authenticationReason = requestReason.toAuthenticationReason()
                            updateAuthenticationState(
                                AuthenticationState.AuthenticationStarted(authenticationReason)
                            )
                                    REASON_ENROLL_FIND_SENSOR ->
                                        AuthenticationReason.SettingsAuthentication(
                                            SettingsOperations.ENROLL_FIND_SENSOR
                                        )
                                    else -> AuthenticationReason.Unknown
                                }
                            updateFingerprintAuthenticateReason(authenticationReason)
                        }

                        override fun onAuthenticationStopped() {
                            updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
                            updateAuthenticationState(
                                AuthenticationState.AuthenticationStopped(
                                    AuthenticationReason.NotRunning
                                )
                            )
                        }

                        override fun onAuthenticationSucceeded(requestReason: Int, userId: Int) {}

                        override fun onAuthenticationFailed(requestReason: Int, userId: Int) {}

                        override fun onAuthenticationAcquired(
                            biometricSourceType: BiometricSourceType,
                            requestReason: Int,
                            acquiredInfo: Int
                        ) {
                            val authReason = requestReason.toAuthenticationReason()

                            updateAuthenticationState(
                                AuthenticationState.AuthenticationAcquired(
                                    biometricSourceType,
                                    authReason,
                                    acquiredInfo
                                )
                            )
                        }
                    }

                updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
                updateAuthenticationState(
                    AuthenticationState.AuthenticationStarted(AuthenticationReason.NotRunning)
                )
                biometricManager?.registerAuthenticationStateListener(authenticationStateListener)
                awaitClose {
                    biometricManager?.unregisterAuthenticationStateListener(
@@ -110,7 +120,36 @@ constructor(
            }
            .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)

    override val fingerprintAuthenticationReason: Flow<AuthenticationReason> =
        authenticationState.map { it.requestReason }

    override val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus> =
        authenticationState
            .filterIsInstance<AuthenticationState.AuthenticationAcquired>()
            .filter {
                it.biometricSourceType == BiometricSourceType.FINGERPRINT &&
                    // TODO(b/322555228) This check will be removed after consolidating device
                    //  entry auth messages (currently in DeviceEntryFingerprintAuthRepository)
                    //  with BP auth messages (here)
                    it.requestReason == AuthenticationReason.BiometricPromptAuthentication
            }
            .map { AcquiredFingerprintAuthenticationStatus(it.requestReason, it.acquiredInfo) }

    companion object {
        private const val TAG = "BiometricStatusRepositoryImpl"
    }
}

private fun Int.toAuthenticationReason(): AuthenticationReason =
    when (this) {
        REASON_AUTH_BP -> AuthenticationReason.BiometricPromptAuthentication
        REASON_AUTH_KEYGUARD -> AuthenticationReason.DeviceEntryAuthentication
        REASON_AUTH_OTHER -> AuthenticationReason.OtherAuthentication
        REASON_AUTH_SETTINGS ->
            AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER)
        REASON_ENROLL_ENROLLING ->
            AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
        REASON_ENROLL_FIND_SENSOR ->
            AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_FIND_SENSOR)
        else -> AuthenticationReason.Unknown
    }
+7 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.ActivityTaskManager
import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
import com.android.systemui.biometrics.shared.model.AuthenticationReason
import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
@@ -31,6 +32,9 @@ interface BiometricStatusInteractor {
     * filtered for when the overlay should be shown, otherwise [NotRunning].
     */
    val sfpsAuthenticationReason: Flow<AuthenticationReason>

    /** The current status of an acquired fingerprint. */
    val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus>
}

class BiometricStatusInteractorImpl
@@ -50,6 +54,9 @@ constructor(
            }
        }

    override val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus> =
        biometricStatusRepository.fingerprintAcquiredStatus

    companion object {
        private const val TAG = "BiometricStatusInteractor"
    }
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.BiometricSourceType

/**
 * Describes the current state of biometric authentication, including whether authentication is
 * started, stopped, or acquired and relevant parameters, and the [AuthenticationReason] for
 * authentication.
 */
sealed interface AuthenticationState {
    val requestReason: AuthenticationReason

    /**
     * Authentication started
     *
     * @param requestReason [AuthenticationReason] for starting authentication
     */
    data class AuthenticationStarted(override val requestReason: AuthenticationReason) :
        AuthenticationState

    /**
     * Authentication stopped
     *
     * @param requestReason [AuthenticationReason.NotRunning]
     */
    data class AuthenticationStopped(override val requestReason: AuthenticationReason) :
        AuthenticationState

    /**
     * Authentication acquired
     *
     * @param biometricSourceType indicates [BiometricSourceType] of acquired authentication
     * @param requestReason indicates [AuthenticationReason] for requesting auth
     * @param acquiredInfo indicates
     */
    data class AuthenticationAcquired(
        val biometricSourceType: BiometricSourceType,
        override val requestReason: AuthenticationReason,
        val acquiredInfo: Int
    ) : AuthenticationState
}
Loading