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