• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.keyguard.domain.interactor
18 
19 import android.content.Context
20 import android.util.Log
21 import com.android.keyguard.KeyguardUpdateMonitor
22 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
23 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
24 import com.android.systemui.dagger.SysUISingleton
25 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
26 import com.android.systemui.res.R
27 import com.android.systemui.scene.domain.interactor.SceneInteractor
28 import com.android.systemui.scene.shared.flag.SceneContainerFlag
29 import com.android.systemui.scene.shared.model.Overlays
30 import com.android.systemui.shade.ShadeDisplayAware
31 import javax.inject.Inject
32 import kotlinx.coroutines.flow.Flow
33 import kotlinx.coroutines.flow.combine
34 import kotlinx.coroutines.flow.distinctUntilChanged
35 import kotlinx.coroutines.flow.filter
36 import kotlinx.coroutines.flow.filterNotNull
37 import kotlinx.coroutines.flow.flowOf
38 import kotlinx.coroutines.flow.map
39 import kotlinx.coroutines.flow.merge
40 import kotlinx.coroutines.flow.onEach
41 
42 /**
43  * Encapsulates business logic for device entry events that impact the side fingerprint sensor
44  * overlay.
45  */
46 @SysUISingleton
47 class DeviceEntrySideFpsOverlayInteractor
48 @Inject
49 constructor(
50     @ShadeDisplayAware private val context: Context,
51     deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
52     private val sceneInteractor: SceneInteractor,
53     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
54     alternateBouncerInteractor: AlternateBouncerInteractor,
55     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
56 ) {
57 
58     private val isSideFpsIndicatorOnPrimaryBouncerEnabled: Boolean
59         get() = context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
60 
61     private val isBouncerOverlayActive: Flow<Boolean> =
62         if (SceneContainerFlag.isEnabled) {
63             sceneInteractor.currentOverlays.map { Overlays.Bouncer in it }.distinctUntilChanged()
64         } else {
65             flowOf(false)
66         }
67 
68     private val showIndicatorForPrimaryBouncer: Flow<Boolean> =
69         merge(
70                 // Legacy bouncer visibility changes.
71                 primaryBouncerInteractor.isShowing,
72                 primaryBouncerInteractor.startingToHide,
73                 primaryBouncerInteractor.startingDisappearAnimation.filterNotNull(),
74                 // Bouncer scene visibility changes.
75                 isBouncerOverlayActive,
76                 deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it },
77             )
78             .map {
79                 isBouncerActive() &&
80                     isSideFpsIndicatorOnPrimaryBouncerEnabled &&
81                     keyguardUpdateMonitor.isFingerprintDetectionRunning &&
82                     keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
83             }
84             .onEach { Log.d(TAG, "showIndicatorForPrimaryBouncer updated: $it") }
85 
86     private val showIndicatorForAlternateBouncer: Flow<Boolean> =
87         // Note: this interactor internally verifies that SideFPS is enabled and running.
88         alternateBouncerInteractor.isVisible.onEach {
89             Log.d(TAG, "showIndicatorForAlternateBouncer updated: $it")
90         }
91 
92     /**
93      * Indicates whether the primary or alternate bouncers request showing the side fingerprint
94      * sensor indicator.
95      */
96     val showIndicatorForDeviceEntry: Flow<Boolean> =
97         combine(showIndicatorForPrimaryBouncer, showIndicatorForAlternateBouncer) {
98                 showForPrimaryBouncer,
99                 showForAlternateBouncer ->
100                 showForPrimaryBouncer || showForAlternateBouncer
101             }
102             .distinctUntilChanged()
103             .onEach { Log.d(TAG, "showIndicatorForDeviceEntry updated: $it") }
104 
105     private fun isBouncerActive(): Boolean {
106         if (SceneContainerFlag.isEnabled) {
107             return Overlays.Bouncer in sceneInteractor.currentOverlays.value
108         }
109         return primaryBouncerInteractor.isBouncerShowing() &&
110             !primaryBouncerInteractor.isAnimatingAway()
111     }
112 
113     companion object {
114         private const val TAG = "DeviceEntrySideFpsOverlayInteractor"
115     }
116 }
117