1 /*
<lambda>null2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.biometrics.domain.interactor
18 
19 import android.app.ActivityTaskManager
20 import android.util.Log
21 import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
22 import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
23 import com.android.systemui.biometrics.shared.model.AuthenticationReason
24 import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
25 import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus
26 import javax.inject.Inject
27 import kotlinx.coroutines.flow.Flow
28 import kotlinx.coroutines.flow.combine
29 import kotlinx.coroutines.flow.distinctUntilChanged
30 import kotlinx.coroutines.flow.onEach
31 
32 /** Encapsulates business logic for interacting with biometric authentication state. */
33 interface BiometricStatusInteractor {
34     /**
35      * The logical reason for the current side fingerprint sensor auth operation if one is on-going,
36      * filtered for when the overlay should be shown, otherwise [NotRunning].
37      */
38     val sfpsAuthenticationReason: Flow<AuthenticationReason>
39 
40     /** The current status of an acquired fingerprint. */
41     val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus>
42 }
43 
44 class BiometricStatusInteractorImpl
45 @Inject
46 constructor(
47     private val activityTaskManager: ActivityTaskManager,
48     biometricStatusRepository: BiometricStatusRepository,
49     fingerprintPropertyRepository: FingerprintPropertyRepository,
50 ) : BiometricStatusInteractor {
51 
52     override val sfpsAuthenticationReason: Flow<AuthenticationReason> =
53         combine(
54                 biometricStatusRepository.fingerprintAuthenticationReason,
55                 fingerprintPropertyRepository.sensorType
reasonnull56             ) { reason: AuthenticationReason, sensorType ->
57                 if (
58                     sensorType.isPowerButton() &&
59                         reason.isReasonToAlwaysUpdateSfpsOverlay(activityTaskManager)
60                 ) {
61                     reason
62                 } else {
63                     AuthenticationReason.NotRunning
64                 }
65             }
66             .distinctUntilChanged()
<lambda>null67             .onEach { Log.d(TAG, "sfpsAuthenticationReason updated: $it") }
68 
69     override val fingerprintAcquiredStatus: Flow<FingerprintAuthenticationStatus> =
70         biometricStatusRepository.fingerprintAcquiredStatus
71 
72     companion object {
73         private const val TAG = "BiometricStatusInteractor"
74     }
75 }
76 
77 /** True if the sfps overlay should always be updated for this request source, false otherwise. */
isReasonToAlwaysUpdateSfpsOverlaynull78 private fun AuthenticationReason.isReasonToAlwaysUpdateSfpsOverlay(
79     activityTaskManager: ActivityTaskManager
80 ): Boolean =
81     when (this) {
82         AuthenticationReason.DeviceEntryAuthentication -> false
83         AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER) ->
84             when (activityTaskManager.topClass()) {
85                 // TODO(b/186176653): exclude fingerprint overlays from this list view
86                 "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false
87                 else -> true
88             }
89         else -> true
90     }
91 
topClassnull92 internal fun ActivityTaskManager.topClass(): String =
93     getTasks(1).firstOrNull()?.topActivity?.className ?: ""
94