• 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.content.res.Resources
20 import android.hardware.biometrics.BiometricFaceConstants
21 import com.android.systemui.biometrics.FaceHelpMessageDebouncer
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.dagger.qualifiers.Application
24 import com.android.systemui.dagger.qualifiers.Main
25 import com.android.systemui.deviceentry.data.repository.DeviceEntryFaceAuthRepository
26 import com.android.systemui.deviceentry.shared.model.AcquiredFaceAuthenticationStatus
27 import com.android.systemui.deviceentry.shared.model.FaceAuthenticationStatus
28 import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
29 import com.android.systemui.res.R
30 import java.util.Arrays
31 import java.util.stream.Collectors
32 import javax.inject.Inject
33 import kotlinx.coroutines.CoroutineScope
34 import kotlinx.coroutines.flow.SharingStarted
35 import kotlinx.coroutines.flow.StateFlow
36 import kotlinx.coroutines.flow.stateIn
37 import kotlinx.coroutines.flow.transform
38 
39 /**
40  * Process face authentication statuses.
41  * - Ignores face help messages based on R.array.config_face_acquire_device_entry_ignorelist.
42  * - Uses FaceHelpMessageDebouncer to debounce flickery help messages.
43  */
44 @SysUISingleton
45 class DeviceEntryFaceAuthStatusInteractor
46 @Inject
47 constructor(
48     repository: DeviceEntryFaceAuthRepository,
49     @Main private val resources: Resources,
50     @Application private val applicationScope: CoroutineScope,
51 ) {
52     private val faceHelpMessageDebouncer = FaceHelpMessageDebouncer()
53     private var faceAcquiredInfoIgnoreList: Set<Int> =
54         Arrays.stream(resources.getIntArray(R.array.config_face_acquire_device_entry_ignorelist))
55             .boxed()
56             .collect(Collectors.toSet())
57 
58     val authenticationStatus: StateFlow<FaceAuthenticationStatus?> =
59         repository.authenticationStatus
60             .transform { authenticationStatus ->
61                 if (authenticationStatus is AcquiredFaceAuthenticationStatus) {
62                     if (
63                         authenticationStatus.acquiredInfo ==
64                             BiometricFaceConstants.FACE_ACQUIRED_START
65                     ) {
66                         faceHelpMessageDebouncer.startNewFaceAuthSession(
67                             authenticationStatus.createdAt
68                         )
69                     }
70                 }
71 
72                 if (authenticationStatus is HelpFaceAuthenticationStatus) {
73                     if (!faceAcquiredInfoIgnoreList.contains(authenticationStatus.msgId)) {
74                         faceHelpMessageDebouncer.addMessage(authenticationStatus)
75                     }
76 
77                     val messageToShow =
78                         faceHelpMessageDebouncer.getMessageToShow(
79                             atTimestamp = authenticationStatus.createdAt,
80                         )
81                     if (messageToShow != null) {
82                         emit(messageToShow)
83                     }
84 
85                     return@transform
86                 }
87 
88                 emit(authenticationStatus)
89             }
90             .stateIn(
91                 scope = applicationScope,
92                 started = SharingStarted.WhileSubscribed(),
93                 initialValue = null,
94             )
95 }
96