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