• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 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.settings.biometrics.fingerprint2.data.repository
18 
19 import android.hardware.biometrics.BiometricStateListener
20 import android.hardware.fingerprint.FingerprintManager
21 import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
22 import kotlinx.coroutines.CoroutineDispatcher
23 import kotlinx.coroutines.CoroutineScope
24 import kotlinx.coroutines.channels.awaitClose
25 import kotlinx.coroutines.flow.Flow
26 import kotlinx.coroutines.flow.MutableStateFlow
27 import kotlinx.coroutines.flow.SharingStarted
28 import kotlinx.coroutines.flow.asStateFlow
29 import kotlinx.coroutines.flow.callbackFlow
30 import kotlinx.coroutines.flow.combine
31 import kotlinx.coroutines.flow.distinctUntilChanged
32 import kotlinx.coroutines.flow.filterNotNull
33 import kotlinx.coroutines.flow.flowOn
34 import kotlinx.coroutines.flow.stateIn
35 import kotlinx.coroutines.flow.update
36 import kotlinx.coroutines.withContext
37 
38 /** Repository that contains information about fingerprint enrollments. */
39 interface FingerprintEnrollmentRepository {
40   /** The current enrollments of the user */
41   val currentEnrollments: Flow<List<FingerprintData>?>
42 
43   /** Indicates the maximum fingerprints that are enrollable * */
44   val maxFingerprintsEnrollable: Flow<Int>
45 
46   /** Indicates if a user can enroll another fingerprint */
47   val canEnrollUser: Flow<Boolean>
48 
49   val enrollStageCount: Int
50 
51   /**
52    * Returns the threshold for the given stage of fingerprint enrollment.
53    *
54    * @param index The index of the enrollment stage.
55    * @return The threshold for the enrollment stage.
56    */
57   fun getEnrollStageThreshold(index: Int): Float
58 
59   /**
60    * Indicates if we should use the default settings for maximum enrollments or the sensor props
61    * from the fingerprint sensor
62    */
63   fun setShouldUseSettingsMaxFingerprints(useSettings: Boolean)
64 }
65 
66 class FingerprintEnrollmentRepositoryImpl(
67   private val fingerprintManager: FingerprintManager,
68   userRepo: UserRepo,
69   settingsRepository: FingerprintSettingsRepository,
70   backgroundDispatcher: CoroutineDispatcher,
71   applicationScope: CoroutineScope,
72   sensorRepo: FingerprintSensorRepository,
73 ) : FingerprintEnrollmentRepository {
74 
75   private val _shouldUseSettingsMaxFingerprints = MutableStateFlow(false)
76   val shouldUseSettingsMaxFingerprints = _shouldUseSettingsMaxFingerprints.asStateFlow()
77 
78   private val enrollmentChangedFlow: Flow<Int?> =
<lambda>null79     callbackFlow {
80         val callback =
81           object : BiometricStateListener() {
82             override fun onEnrollmentsChanged(userId: Int, sensorId: Int, hasEnrollments: Boolean) {
83               trySend(userId)
84             }
85           }
86         withContext(backgroundDispatcher) {
87           fingerprintManager.registerBiometricStateListener(callback)
88         }
89         awaitClose {
90           // no way to unregister
91         }
92       }
93       .stateIn(applicationScope, started = SharingStarted.Eagerly, initialValue = null)
94 
95   override val currentEnrollments: Flow<List<FingerprintData>> =
96     userRepo.currentUser
97       .distinctUntilChanged()
currentUsernull98       .combine(enrollmentChangedFlow) { currentUser, _ -> getFingerprintsForUser(currentUser) }
99       .filterNotNull()
100       .flowOn(backgroundDispatcher)
101 
102   override val maxFingerprintsEnrollable: Flow<Int> =
103     shouldUseSettingsMaxFingerprints.combine(sensorRepo.fingerprintSensor) {
shouldUseSettingsnull104       shouldUseSettings,
105       sensor ->
106       if (shouldUseSettings) {
107         settingsRepository.maxEnrollableFingerprints()
108       } else {
109         sensor.maxEnrollmentsPerUser
110       }
111     }
112 
113   override val canEnrollUser: Flow<Boolean> =
enrollmentsnull114     currentEnrollments.combine(maxFingerprintsEnrollable) { enrollments, maxFingerprints ->
115       enrollments.size < maxFingerprints
116     }
117 
setShouldUseSettingsMaxFingerprintsnull118   override fun setShouldUseSettingsMaxFingerprints(useSettings: Boolean) {
119     _shouldUseSettingsMaxFingerprints.update { useSettings }
120   }
121 
getFingerprintsForUsernull122   private fun getFingerprintsForUser(userId: Int): List<FingerprintData>? {
123     return fingerprintManager
124       .getEnrolledFingerprints(userId)
125       ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }
126       ?.toList()
127   }
128 
129   override val enrollStageCount: Int
130     get() = fingerprintManager.enrollStageCount
131 
getEnrollStageThresholdnull132   override fun getEnrollStageThreshold(index: Int): Float =
133     fingerprintManager.getEnrollStageThreshold(index)
134 }
135