1 /*
2  * Copyright (C) 2022 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.bouncer.domain.interactor
18 
19 import com.android.keyguard.KeyguardUpdateMonitor
20 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
21 import com.android.systemui.dagger.SysUISingleton
22 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
23 import com.android.systemui.plugins.statusbar.StatusBarStateController
24 import com.android.systemui.statusbar.policy.KeyguardStateController
25 import com.android.systemui.util.time.SystemClock
26 import javax.inject.Inject
27 import kotlinx.coroutines.flow.Flow
28 
29 /** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */
30 @SysUISingleton
31 class AlternateBouncerInteractor
32 @Inject
33 constructor(
34     private val statusBarStateController: StatusBarStateController,
35     private val keyguardStateController: KeyguardStateController,
36     private val bouncerRepository: KeyguardBouncerRepository,
37     private val biometricSettingsRepository: BiometricSettingsRepository,
38     private val systemClock: SystemClock,
39     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
40 ) {
41     var receivedDownTouch = false
42     val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
43     private val alternateBouncerUiAvailableFromSource: HashSet<String> = HashSet()
44 
45     /**
46      * Sets the correct bouncer states to show the alternate bouncer if it can show.
47      *
48      * @return whether alternateBouncer is visible
49      */
50     fun show(): Boolean {
51         bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint())
52         return isVisibleState()
53     }
54 
55     /**
56      * Sets the correct bouncer states to hide the bouncer. Should only be called through
57      * StatusBarKeyguardViewManager until ScrimController is refactored to use
58      * alternateBouncerInteractor.
59      *
60      * @return true if the alternate bouncer was newly hidden, else false.
61      */
62     fun hide(): Boolean {
63         receivedDownTouch = false
64         val wasAlternateBouncerVisible = isVisibleState()
65         bouncerRepository.setAlternateVisible(false)
66         return wasAlternateBouncerVisible && !isVisibleState()
67     }
68 
69     fun isVisibleState(): Boolean {
70         return bouncerRepository.alternateBouncerVisible.value
71     }
72 
73     fun setAlternateBouncerUIAvailable(isAvailable: Boolean, token: String) {
74         if (isAvailable) {
75             alternateBouncerUiAvailableFromSource.add(token)
76         } else {
77             alternateBouncerUiAvailableFromSource.remove(token)
78         }
79         bouncerRepository.setAlternateBouncerUIAvailable(
80             alternateBouncerUiAvailableFromSource.isNotEmpty()
81         )
82     }
83 
84     fun canShowAlternateBouncerForFingerprint(): Boolean {
85         return bouncerRepository.alternateBouncerUIAvailable.value &&
86             biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value &&
87             !keyguardUpdateMonitor.isFingerprintLockedOut &&
88             !keyguardStateController.isUnlocked &&
89             !statusBarStateController.isDozing
90     }
91 
92     /**
93      * Whether the alt bouncer has shown for a minimum time before allowing touches to dismiss the
94      * alternate bouncer and show the primary bouncer.
95      */
96     fun hasAlternateBouncerShownWithMinTime(): Boolean {
97         return (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) >
98             MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS
99     }
100     /**
101      * Should only be called through StatusBarKeyguardViewManager which propagates the source of
102      * truth to other concerned controllers. Will hide the alternate bouncer if it's no longer
103      * allowed to show.
104      *
105      * @return true if the alternate bouncer was newly hidden, else false.
106      */
107     fun maybeHide(): Boolean {
108         if (isVisibleState() && !canShowAlternateBouncerForFingerprint()) {
109             return hide()
110         }
111         return false
112     }
113 
114     companion object {
115         private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L
116     }
117 }
118