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