• 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.systemui.deviceentry.domain.interactor
18 
19 import android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START
20 import android.hardware.face.FaceManager
21 import com.android.systemui.biometrics.FaceHelpMessageDeferralFactory
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.dagger.qualifiers.Application
24 import com.android.systemui.deviceentry.shared.model.AcquiredFaceAuthenticationStatus
25 import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
26 import javax.inject.Inject
27 import kotlinx.coroutines.CoroutineScope
28 import kotlinx.coroutines.flow.Flow
29 import kotlinx.coroutines.flow.emptyFlow
30 import kotlinx.coroutines.flow.filterIsInstance
31 import kotlinx.coroutines.flow.flatMapLatest
32 import com.android.app.tracing.coroutines.launchTraced as launch
33 
34 /**
35  * FaceHelpMessageDeferral business logic. Processes face acquired and face help authentication
36  * events to determine whether a face auth event should be displayed to the user immediately or when
37  * a [FaceManager.FACE_ERROR_TIMEOUT] is received.
38  */
39 @SysUISingleton
40 class FaceHelpMessageDeferralInteractor
41 @Inject
42 constructor(
43     @Application private val scope: CoroutineScope,
44     faceAuthInteractor: DeviceEntryFaceAuthInteractor,
45     private val biometricSettingsInteractor: DeviceEntryBiometricSettingsInteractor,
46     faceHelpMessageDeferralFactory: FaceHelpMessageDeferralFactory,
47 ) {
48     private val faceHelpMessageDeferral = faceHelpMessageDeferralFactory.create()
49     private val faceAcquired: Flow<AcquiredFaceAuthenticationStatus> =
50         faceAuthInteractor.authenticationStatus.filterIsInstance<AcquiredFaceAuthenticationStatus>()
51     private val faceHelp: Flow<HelpFaceAuthenticationStatus> =
52         faceAuthInteractor.authenticationStatus.filterIsInstance<HelpFaceAuthenticationStatus>()
53 
54     init {
55         startUpdatingFaceHelpMessageDeferral()
56     }
57 
58     /**
59      * If the given [HelpFaceAuthenticationStatus] msgId should be deferred to
60      * [FaceManager.FACE_ERROR_TIMEOUT].
61      */
62     fun shouldDefer(msgId: Int): Boolean {
63         return faceHelpMessageDeferral.shouldDefer(msgId)
64     }
65 
66     /**
67      * Message that was deferred to show at [FaceManager.FACE_ERROR_TIMEOUT], if any. Returns null
68      * if there are currently no valid deferred messages.
69      */
70     fun getDeferredMessage(): CharSequence? {
71         return faceHelpMessageDeferral.getDeferredMessage()
72     }
73 
74     private fun startUpdatingFaceHelpMessageDeferral() {
75         scope.launch {
76             biometricSettingsInteractor.isFaceAuthEnrolledAndEnabled
77                 .flatMapLatest { faceEnrolledAndEnabled ->
78                     if (faceEnrolledAndEnabled) {
79                         faceAcquired
80                     } else {
81                         emptyFlow()
82                     }
83                 }
84                 .collect {
85                     if (it.acquiredInfo == FACE_ACQUIRED_START) {
86                         faceHelpMessageDeferral.reset()
87                     }
88                     faceHelpMessageDeferral.processFrame(it.acquiredInfo)
89                 }
90         }
91 
92         scope.launch {
93             biometricSettingsInteractor.isFaceAuthEnrolledAndEnabled
94                 .flatMapLatest { faceEnrolledAndEnabled ->
95                     if (faceEnrolledAndEnabled) {
96                         faceHelp
97                     } else {
98                         emptyFlow()
99                     }
100                 }
101                 .collect { helpAuthenticationStatus ->
102                     helpAuthenticationStatus.msg?.let { msg ->
103                         faceHelpMessageDeferral.updateMessage(helpAuthenticationStatus.msgId, msg)
104                     }
105                 }
106         }
107     }
108 }
109