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.deviceentry.domain.interactor
18 
19 import com.android.systemui.dagger.SysUISingleton
20 import com.android.systemui.deviceentry.shared.DeviceEntryBiometricMode
21 import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
22 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
23 import javax.inject.Inject
24 import kotlinx.coroutines.ExperimentalCoroutinesApi
25 import kotlinx.coroutines.flow.Flow
26 import kotlinx.coroutines.flow.combine
27 import kotlinx.coroutines.flow.emptyFlow
28 import kotlinx.coroutines.flow.filterIsInstance
29 import kotlinx.coroutines.flow.flatMapLatest
30 import kotlinx.coroutines.flow.map
31 
32 /** Business logic for device entry biometric states that may differ based on the biometric mode. */
33 @ExperimentalCoroutinesApi
34 @SysUISingleton
35 class DeviceEntryBiometricAuthInteractor
36 @Inject
37 constructor(
38     biometricSettingsRepository: BiometricSettingsRepository,
39     deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
40 ) {
41     private val biometricMode: Flow<DeviceEntryBiometricMode> =
42         combine(
43             biometricSettingsRepository.isFingerprintEnrolledAndEnabled,
44             biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
45         ) { fingerprintEnrolled, faceEnrolled ->
46             if (fingerprintEnrolled && faceEnrolled) {
47                 DeviceEntryBiometricMode.CO_EXPERIENCE
48             } else if (fingerprintEnrolled) {
49                 DeviceEntryBiometricMode.FINGERPRINT_ONLY
50             } else if (faceEnrolled) {
51                 DeviceEntryBiometricMode.FACE_ONLY
52             } else {
53                 DeviceEntryBiometricMode.NONE
54             }
55         }
56     private val faceOnly: Flow<Boolean> =
57         biometricMode.map { it == DeviceEntryBiometricMode.FACE_ONLY }
58 
59     /**
60      * Triggered if face is the only biometric that can be used for device entry and a face failure
61      * occurs.
62      */
63     val faceOnlyFaceFailure: Flow<FailedFaceAuthenticationStatus> =
64         faceOnly.flatMapLatest { faceOnly ->
65             if (faceOnly) {
66                 deviceEntryFaceAuthInteractor.authenticationStatus.filterIsInstance<
67                     FailedFaceAuthenticationStatus
68                 >()
69             } else {
70                 emptyFlow()
71             }
72         }
73 }
74