• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.keyguard.domain.interactor
18 
19 import com.android.keyguard.KeyguardUpdateMonitor
20 import com.android.systemui.dagger.SysUISingleton
21 import com.android.systemui.flags.FeatureFlags
22 import com.android.systemui.flags.Flags
23 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
24 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
25 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
26 import com.android.systemui.plugins.statusbar.StatusBarStateController
27 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
28 import com.android.systemui.statusbar.policy.KeyguardStateController
29 import com.android.systemui.util.time.SystemClock
30 import javax.inject.Inject
31 import kotlinx.coroutines.flow.Flow
32 
33 /** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */
34 @SysUISingleton
35 class AlternateBouncerInteractor
36 @Inject
37 constructor(
38     private val statusBarStateController: StatusBarStateController,
39     private val keyguardStateController: KeyguardStateController,
40     private val bouncerRepository: KeyguardBouncerRepository,
41     private val biometricSettingsRepository: BiometricSettingsRepository,
42     private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
43     private val systemClock: SystemClock,
44     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
45     featureFlags: FeatureFlags,
46 ) {
47     val isModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER)
48     var legacyAlternateBouncer: LegacyAlternateBouncer? = null
49     var legacyAlternateBouncerVisibleTime: Long = NOT_VISIBLE
50 
51     val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
52 
53     private val keyguardStateControllerCallback: KeyguardStateController.Callback =
54         object : KeyguardStateController.Callback {
onUnlockedChangednull55             override fun onUnlockedChanged() {
56                 maybeHide()
57             }
58         }
59 
60     init {
61         keyguardStateController.addCallback(keyguardStateControllerCallback)
62     }
63 
64     /**
65      * Sets the correct bouncer states to show the alternate bouncer if it can show.
66      *
67      * @return whether alternateBouncer is visible
68      */
shownull69     fun show(): Boolean {
70         return when {
71             isModernAlternateBouncerEnabled -> {
72                 bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint())
73                 isVisibleState()
74             }
75             canShowAlternateBouncerForFingerprint() -> {
76                 if (legacyAlternateBouncer?.showAlternateBouncer() == true) {
77                     legacyAlternateBouncerVisibleTime = systemClock.uptimeMillis()
78                     true
79                 } else {
80                     false
81                 }
82             }
83             else -> false
84         }
85     }
86 
87     /**
88      * Sets the correct bouncer states to hide the bouncer. Should only be called through
89      * StatusBarKeyguardViewManager until ScrimController is refactored to use
90      * alternateBouncerInteractor.
91      *
92      * @return true if the alternate bouncer was newly hidden, else false.
93      */
hidenull94     fun hide(): Boolean {
95         return if (isModernAlternateBouncerEnabled) {
96             val wasAlternateBouncerVisible = isVisibleState()
97             bouncerRepository.setAlternateVisible(false)
98             wasAlternateBouncerVisible && !isVisibleState()
99         } else {
100             legacyAlternateBouncer?.hideAlternateBouncer() ?: false
101         }
102     }
103 
isVisibleStatenull104     fun isVisibleState(): Boolean {
105         return if (isModernAlternateBouncerEnabled) {
106             bouncerRepository.alternateBouncerVisible.value
107         } else {
108             legacyAlternateBouncer?.isShowingAlternateBouncer ?: false
109         }
110     }
111 
setAlternateBouncerUIAvailablenull112     fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
113         bouncerRepository.setAlternateBouncerUIAvailable(isAvailable)
114     }
115 
canShowAlternateBouncerForFingerprintnull116     fun canShowAlternateBouncerForFingerprint(): Boolean {
117         return if (isModernAlternateBouncerEnabled) {
118             bouncerRepository.alternateBouncerUIAvailable.value &&
119                 biometricSettingsRepository.isFingerprintEnrolled.value &&
120                 biometricSettingsRepository.isStrongBiometricAllowed.value &&
121                 biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
122                 !deviceEntryFingerprintAuthRepository.isLockedOut.value &&
123                 !keyguardStateController.isUnlocked &&
124                 !statusBarStateController.isDozing
125         } else {
126             legacyAlternateBouncer != null &&
127                 keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true)
128         }
129     }
130 
131     /**
132      * Whether the alt bouncer has shown for a minimum time before allowing touches to dismiss the
133      * alternate bouncer and show the primary bouncer.
134      */
hasAlternateBouncerShownWithMinTimenull135     fun hasAlternateBouncerShownWithMinTime(): Boolean {
136         return if (isModernAlternateBouncerEnabled) {
137             (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) >
138                 MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS
139         } else {
140             systemClock.uptimeMillis() - legacyAlternateBouncerVisibleTime > 200
141         }
142     }
143 
maybeHidenull144     private fun maybeHide() {
145         if (isVisibleState() && !canShowAlternateBouncerForFingerprint()) {
146             hide()
147         }
148     }
149 
150     companion object {
151         private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L
152         private const val NOT_VISIBLE = -1L
153     }
154 }
155