1 /* 2 * 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 javax.inject.Inject 37 import kotlinx.coroutines.CoroutineScope 38 import kotlinx.coroutines.channels.awaitClose 39 import kotlinx.coroutines.flow.Flow 40 import kotlinx.coroutines.flow.SharingStarted 41 import kotlinx.coroutines.flow.StateFlow 42 import kotlinx.coroutines.flow.map 43 import kotlinx.coroutines.flow.stateIn 44 45 /** 46 * A repository for the global state of FingerprintProperty. 47 * 48 * There is never more than one instance of the FingerprintProperty at any given time. 49 */ 50 interface FingerprintPropertyRepository { 51 52 /** The id of fingerprint sensor. */ 53 val sensorId: Flow<Int> 54 55 /** The security strength of sensor (convenience, weak, strong). */ 56 val strength: Flow<SensorStrength> 57 58 /** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */ 59 val sensorType: Flow<FingerprintSensorType> 60 61 /** The sensor location relative to each physical display. */ 62 val sensorLocations: Flow<Map<String, SensorLocationInternal>> 63 } 64 65 @SysUISingleton 66 class FingerprintPropertyRepositoryImpl 67 @Inject 68 constructor( 69 @Application private val applicationScope: CoroutineScope, 70 private val fingerprintManager: FingerprintManager?, 71 ) : FingerprintPropertyRepository { 72 73 @RequiresPermission(USE_BIOMETRIC_INTERNAL) 74 private val props: StateFlow<FingerprintSensorPropertiesInternal> = 75 conflatedCallbackFlow { 76 val callback = 77 object : IFingerprintAuthenticatorsRegisteredCallback.Stub() { 78 override fun onAllAuthenticatorsRegistered( 79 sensors: List<FingerprintSensorPropertiesInternal> 80 ) { 81 if (sensors.isEmpty()) { 82 trySendWithFailureLogging( 83 DEFAULT_PROPS, 84 TAG, 85 "no registered sensors, use default props" 86 ) 87 } else { 88 trySendWithFailureLogging( 89 sensors[0], 90 TAG, 91 "update properties on authenticators registered" 92 ) 93 } 94 } 95 } 96 fingerprintManager?.addAuthenticatorsRegisteredCallback(callback) 97 awaitClose {} 98 } 99 .stateIn( 100 applicationScope, 101 started = SharingStarted.Eagerly, 102 initialValue = DEFAULT_PROPS, 103 ) 104 105 override val sensorId: Flow<Int> = props.map { it.sensorId } 106 107 override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() } 108 109 override val sensorType: Flow<FingerprintSensorType> = 110 props.map { it.sensorType.toSensorType() } 111 112 override val sensorLocations: Flow<Map<String, SensorLocationInternal>> = 113 props.map { 114 it.allLocations.associateBy { sensorLocationInternal -> 115 sensorLocationInternal.displayId 116 } 117 } 118 119 companion object { 120 private const val TAG = "FingerprintPropertyRepositoryImpl" 121 private val DEFAULT_PROPS = 122 FingerprintSensorPropertiesInternal( 123 -1 /* sensorId */, 124 SensorProperties.STRENGTH_CONVENIENCE, 125 0 /* maxEnrollmentsPerUser */, 126 listOf<ComponentInfoInternal>(), 127 FingerprintSensorProperties.TYPE_UNKNOWN, 128 false /* halControlsIllumination */, 129 true /* resetLockoutRequiresHardwareAuthToken */, 130 listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT) 131 ) 132 } 133 } 134