• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.data.repository
18 
19 import android.Manifest.permission.USE_BIOMETRIC_INTERNAL
20 import android.annotation.RequiresPermission
21 import android.hardware.biometrics.ComponentInfoInternal
22 import android.hardware.biometrics.SensorLocationInternal
23 import android.hardware.biometrics.SensorProperties
24 import android.hardware.fingerprint.FingerprintManager
25 import android.hardware.fingerprint.FingerprintSensorProperties
26 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
27 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
28 import com.android.systemui.biometrics.shared.model.FingerprintSensorType
29 import com.android.systemui.biometrics.shared.model.SensorStrength
30 import com.android.systemui.biometrics.shared.model.toSensorStrength
31 import com.android.systemui.biometrics.shared.model.toSensorType
32 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
33 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
34 import com.android.systemui.dagger.SysUISingleton
35 import com.android.systemui.dagger.qualifiers.Application
36 import com.android.systemui.dagger.qualifiers.Background
37 import javax.inject.Inject
38 import kotlinx.coroutines.CoroutineDispatcher
39 import kotlinx.coroutines.CoroutineScope
40 import kotlinx.coroutines.channels.awaitClose
41 import kotlinx.coroutines.flow.Flow
42 import kotlinx.coroutines.flow.SharingStarted
43 import kotlinx.coroutines.flow.StateFlow
44 import kotlinx.coroutines.flow.combine
45 import kotlinx.coroutines.flow.distinctUntilChanged
46 import kotlinx.coroutines.flow.map
47 import kotlinx.coroutines.flow.onStart
48 import kotlinx.coroutines.flow.stateIn
49 import kotlinx.coroutines.withContext
50 
51 /**
52  * A repository for the global state of FingerprintProperty.
53  *
54  * There is never more than one instance of the FingerprintProperty at any given time.
55  */
56 interface FingerprintPropertyRepository {
57     /** Whether the fingerprint properties have been initialized yet. */
58     val propertiesInitialized: Flow<Boolean>
59 
60     /** The id of fingerprint sensor. */
61     val sensorId: Flow<Int>
62 
63     /** The security strength of sensor (convenience, weak, strong). */
64     val strength: Flow<SensorStrength>
65 
66     /** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */
67     val sensorType: StateFlow<FingerprintSensorType>
68 
69     /** The sensor location relative to each physical display. */
70     val sensorLocations: Flow<Map<String, SensorLocationInternal>>
71 }
72 
73 @SysUISingleton
74 class FingerprintPropertyRepositoryImpl
75 @Inject
76 constructor(
77     @Application private val applicationScope: CoroutineScope,
78     @Background private val backgroundDispatcher: CoroutineDispatcher,
79     private val fingerprintManager: FingerprintManager?,
80 ) : FingerprintPropertyRepository {
81 
82     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
83     private val props: StateFlow<FingerprintSensorPropertiesInternal> =
<lambda>null84         conflatedCallbackFlow {
85                 val callback =
86                     object : IFingerprintAuthenticatorsRegisteredCallback.Stub() {
87                         override fun onAllAuthenticatorsRegistered(
88                             sensors: List<FingerprintSensorPropertiesInternal>
89                         ) {
90                             if (sensors.isEmpty()) {
91                                 trySendWithFailureLogging(
92                                     DEFAULT_PROPS,
93                                     TAG,
94                                     "no registered sensors, use default props"
95                                 )
96                             } else {
97                                 trySendWithFailureLogging(
98                                     sensors[0],
99                                     TAG,
100                                     "update properties on authenticators registered"
101                                 )
102                             }
103                         }
104                     }
105                 withContext(backgroundDispatcher) {
106                     fingerprintManager?.addAuthenticatorsRegisteredCallback(callback)
107                 }
108                 awaitClose {}
109             }
110             .stateIn(
111                 applicationScope,
112                 started = SharingStarted.Eagerly,
113                 initialValue = UNINITIALIZED_PROPS,
114             )
115 
<lambda>null116     override val sensorId: Flow<Int> = props.map { it.sensorId }
117 
<lambda>null118     override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() }
119 
120     override val sensorType: StateFlow<FingerprintSensorType> =
121         props
<lambda>null122             .map { it.sensorType.toSensorType() }
123             .stateIn(
124                 scope = applicationScope,
125                 started = SharingStarted.WhileSubscribed(),
126                 initialValue = props.value.sensorType.toSensorType(),
127             )
128 
129     override val sensorLocations: Flow<Map<String, SensorLocationInternal>> =
<lambda>null130         props.map {
131             it.allLocations.associateBy { sensorLocationInternal ->
132                 sensorLocationInternal.displayId
133             }
134         }
135 
136     override val propertiesInitialized: Flow<Boolean> =
137         combine(
138                 props
<lambda>null139                     .map { it != UNINITIALIZED_PROPS }
<lambda>null140                     .onStart { emit(props.value != UNINITIALIZED_PROPS) },
<lambda>null141                 sensorId.map {}.onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
142                 sensorLocations
<lambda>null143                     .map {}
<lambda>null144                     .onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
<lambda>null145                 sensorType.map {}.onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
<lambda>null146                 strength.map {}.onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
initializednull147             ) { initialized, _, _, _, _ ->
148                 initialized
149             }
150             .distinctUntilChanged()
151 
152     companion object {
153         private const val TAG = "FingerprintPropertyRepositoryImpl"
154         private val UNINITIALIZED_PROPS =
155             FingerprintSensorPropertiesInternal(
156                 -2 /* sensorId */,
157                 SensorProperties.STRENGTH_CONVENIENCE,
158                 0 /* maxEnrollmentsPerUser */,
159                 listOf<ComponentInfoInternal>(),
160                 FingerprintSensorProperties.TYPE_UNKNOWN,
161                 false /* halControlsIllumination */,
162                 true /* resetLockoutRequiresHardwareAuthToken */,
163                 listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
164             )
165         private val DEFAULT_PROPS =
166             FingerprintSensorPropertiesInternal(
167                 -1 /* sensorId */,
168                 SensorProperties.STRENGTH_CONVENIENCE,
169                 0 /* maxEnrollmentsPerUser */,
170                 listOf<ComponentInfoInternal>(),
171                 FingerprintSensorProperties.TYPE_UNKNOWN,
172                 false /* halControlsIllumination */,
173                 true /* resetLockoutRequiresHardwareAuthToken */,
174                 listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
175             )
176     }
177 }
178