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.data.repository
18 
19 import android.os.Build
20 import android.util.Log
21 import com.android.keyguard.KeyguardSecurityModel
22 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
23 import com.android.systemui.bouncer.shared.model.BouncerDismissActionModel
24 import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
25 import com.android.systemui.dagger.SysUISingleton
26 import com.android.systemui.dagger.qualifiers.Application
27 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
28 import com.android.systemui.log.dagger.BouncerTableLog
29 import com.android.systemui.log.table.TableLogBuffer
30 import com.android.systemui.log.table.logDiffsForTable
31 import com.android.systemui.util.time.SystemClock
32 import javax.inject.Inject
33 import kotlinx.coroutines.CoroutineScope
34 import kotlinx.coroutines.flow.Flow
35 import kotlinx.coroutines.flow.MutableSharedFlow
36 import kotlinx.coroutines.flow.MutableStateFlow
37 import kotlinx.coroutines.flow.StateFlow
38 import kotlinx.coroutines.flow.asSharedFlow
39 import kotlinx.coroutines.flow.asStateFlow
40 import kotlinx.coroutines.flow.filterNotNull
41 import kotlinx.coroutines.flow.launchIn
42 import kotlinx.coroutines.flow.map
43 import kotlinx.coroutines.flow.onEach
44 
45 /**
46  * Encapsulates app state for the lock screen primary and alternate bouncer.
47  *
48  * Make sure to add newly added flows to the logger.
49  */
50 interface KeyguardBouncerRepository {
51     /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
52     val primaryBouncerShow: StateFlow<Boolean>
53     val primaryBouncerShowingSoon: StateFlow<Boolean>
54     val primaryBouncerStartingToHide: StateFlow<Boolean>
55     val primaryBouncerStartingDisappearAnimation: StateFlow<Runnable?>
56 
57     /** Determines if we want to instantaneously show the primary bouncer instead of translating. */
58     val primaryBouncerScrimmed: StateFlow<Boolean>
59 
60     /**
61      * Set how much of the notification panel is showing on the screen.
62      *
63      * ```
64      *      0f = panel fully hidden = bouncer fully showing
65      *      1f = panel fully showing = bouncer fully hidden
66      * ```
67      */
68     val panelExpansionAmount: StateFlow<Float>
69     val keyguardPosition: StateFlow<Float?>
70     val isBackButtonEnabled: StateFlow<Boolean?>
71 
72     /**
73      * Triggers when the user has successfully used biometrics to authenticate. True = biometrics
74      * used to authenticate is Class 3, else false. When null, biometrics haven't authenticated the
75      * device.
76      */
77     val keyguardAuthenticatedBiometrics: StateFlow<Boolean?>
78 
79     /**
80      * Triggers when the given userId (Int) has successfully used primary authentication to
81      * authenticate
82      */
83     val keyguardAuthenticatedPrimaryAuth: Flow<Int>
84 
85     /** Triggers when the given userId (Int) has requested the bouncer when already authenticated */
86     val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int>
87 
88     val showMessage: StateFlow<BouncerShowMessageModel?>
89     val resourceUpdateRequests: StateFlow<Boolean>
90     val alternateBouncerVisible: StateFlow<Boolean>
91     val alternateBouncerUIAvailable: StateFlow<Boolean>
92 
93     /** Last shown security mode of the primary bouncer (ie: pin/pattern/password/SIM) */
94     val lastShownSecurityMode: StateFlow<KeyguardSecurityModel.SecurityMode>
95 
96     /** Action that should be run right after the bouncer is dismissed. */
97     var bouncerDismissActionModel: BouncerDismissActionModel?
98 
99     var lastAlternateBouncerVisibleTime: Long
100 
setPrimaryScrimmednull101     fun setPrimaryScrimmed(isScrimmed: Boolean)
102 
103     fun setPrimaryShow(isShowing: Boolean)
104 
105     fun setPrimaryShowingSoon(showingSoon: Boolean)
106 
107     fun setPrimaryStartingToHide(startingToHide: Boolean)
108 
109     fun setPrimaryStartDisappearAnimation(runnable: Runnable?)
110 
111     fun setPanelExpansion(panelExpansion: Float)
112 
113     fun setKeyguardPosition(keyguardPosition: Float)
114 
115     fun setResourceUpdateRequests(willUpdateResources: Boolean)
116 
117     fun setShowMessage(bouncerShowMessageModel: BouncerShowMessageModel?)
118 
119     fun setKeyguardAuthenticatedBiometrics(keyguardAuthenticatedBiometrics: Boolean?)
120 
121     suspend fun setKeyguardAuthenticatedPrimaryAuth(userId: Int)
122 
123     suspend fun setUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int)
124 
125     fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean)
126 
127     fun setAlternateVisible(isVisible: Boolean)
128 
129     fun setAlternateBouncerUIAvailable(isAvailable: Boolean)
130 
131     fun setLastShownSecurityMode(securityMode: KeyguardSecurityModel.SecurityMode)
132 }
133 
134 @SysUISingleton
135 class KeyguardBouncerRepositoryImpl
136 @Inject
137 constructor(
138     private val clock: SystemClock,
139     @Application private val applicationScope: CoroutineScope,
140     @BouncerTableLog private val buffer: TableLogBuffer,
141 ) : KeyguardBouncerRepository {
142     override var bouncerDismissActionModel: BouncerDismissActionModel? = null
143 
144     /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
145     private val _primaryBouncerShow = MutableStateFlow(false)
146     override val primaryBouncerShow = _primaryBouncerShow.asStateFlow()
147     private val _primaryBouncerShowingSoon = MutableStateFlow(false)
148     override val primaryBouncerShowingSoon = _primaryBouncerShowingSoon.asStateFlow()
149     private val _primaryBouncerStartingToHide = MutableStateFlow(false)
150     override val primaryBouncerStartingToHide = _primaryBouncerStartingToHide.asStateFlow()
151     private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null)
152     override val primaryBouncerStartingDisappearAnimation =
153         _primaryBouncerDisappearAnimation.asStateFlow()
154 
155     /** Determines if we want to instantaneously show the primary bouncer instead of translating. */
156     private val _primaryBouncerScrimmed = MutableStateFlow(false)
157     override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow()
158 
159     /**
160      * Set how much of the notification panel is showing on the screen.
161      *
162      * ```
163      *      0f = panel fully hidden = bouncer fully showing
164      *      1f = panel fully showing = bouncer fully hidden
165      * ```
166      */
167     private val _panelExpansionAmount = MutableStateFlow(EXPANSION_HIDDEN)
168     override val panelExpansionAmount = _panelExpansionAmount.asStateFlow()
169     private val _keyguardPosition = MutableStateFlow<Float?>(null)
170     override val keyguardPosition = _keyguardPosition.asStateFlow()
171     private val _isBackButtonEnabled = MutableStateFlow<Boolean?>(null)
172     override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow()
173 
174     /** Whether the user is already unlocked by biometrics */
175     private val _keyguardAuthenticatedBiometrics = MutableStateFlow<Boolean?>(null)
176     override val keyguardAuthenticatedBiometrics = _keyguardAuthenticatedBiometrics.asStateFlow()
177 
178     /** Whether the user is unlocked via a primary authentication method (pin/pattern/password). */
179     private val _keyguardAuthenticatedPrimaryAuth = MutableSharedFlow<Int>()
180     override val keyguardAuthenticatedPrimaryAuth: Flow<Int> =
181         _keyguardAuthenticatedPrimaryAuth.asSharedFlow()
182 
183     /** Whether the user requested to show the bouncer when device is already authenticated */
184     private val _userRequestedBouncerWhenAlreadyAuthenticated = MutableSharedFlow<Int>()
185     override val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
186         _userRequestedBouncerWhenAlreadyAuthenticated.asSharedFlow()
187 
188     private val _showMessage = MutableStateFlow<BouncerShowMessageModel?>(null)
189     override val showMessage = _showMessage.asStateFlow()
190     private val _lastShownSecurityMode =
191         MutableStateFlow(KeyguardSecurityModel.SecurityMode.Invalid)
192     override val lastShownSecurityMode: StateFlow<KeyguardSecurityModel.SecurityMode> =
193         _lastShownSecurityMode.asStateFlow()
194 
195     private val _resourceUpdateRequests = MutableStateFlow(false)
196     override val resourceUpdateRequests = _resourceUpdateRequests.asStateFlow()
197 
198     /** Values associated with the AlternateBouncer */
199     private val _alternateBouncerVisible = MutableStateFlow(false)
200     override val alternateBouncerVisible = _alternateBouncerVisible.asStateFlow()
201     override var lastAlternateBouncerVisibleTime: Long = NOT_VISIBLE
202     private val _alternateBouncerUIAvailable = MutableStateFlow(false)
203     override val alternateBouncerUIAvailable: StateFlow<Boolean> =
204         _alternateBouncerUIAvailable.asStateFlow()
205 
206     init {
207         setUpLogging()
208     }
209 
210     override fun setPrimaryScrimmed(isScrimmed: Boolean) {
211         _primaryBouncerScrimmed.value = isScrimmed
212     }
213 
214     override fun setAlternateVisible(isVisible: Boolean) {
215         if (isVisible && !_alternateBouncerVisible.value) {
216             lastAlternateBouncerVisibleTime = clock.uptimeMillis()
217         } else if (!isVisible) {
218             lastAlternateBouncerVisibleTime = NOT_VISIBLE
219         }
220         _alternateBouncerVisible.value = isVisible
221     }
222 
223     override fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
224         DeviceEntryUdfpsRefactor.assertInLegacyMode()
225         _alternateBouncerUIAvailable.value = isAvailable
226     }
227 
228     override fun setPrimaryShow(isShowing: Boolean) {
229         _primaryBouncerShow.value = isShowing
230     }
231 
232     override fun setPrimaryShowingSoon(showingSoon: Boolean) {
233         _primaryBouncerShowingSoon.value = showingSoon
234     }
235 
236     override fun setPrimaryStartingToHide(startingToHide: Boolean) {
237         _primaryBouncerStartingToHide.value = startingToHide
238     }
239 
240     override fun setPrimaryStartDisappearAnimation(runnable: Runnable?) {
241         _primaryBouncerDisappearAnimation.value = runnable
242     }
243 
244     override fun setPanelExpansion(panelExpansion: Float) {
245         _panelExpansionAmount.value = panelExpansion
246     }
247 
248     override fun setKeyguardPosition(keyguardPosition: Float) {
249         _keyguardPosition.value = keyguardPosition
250     }
251 
252     override fun setResourceUpdateRequests(willUpdateResources: Boolean) {
253         _resourceUpdateRequests.value = willUpdateResources
254     }
255 
256     override fun setShowMessage(bouncerShowMessageModel: BouncerShowMessageModel?) {
257         _showMessage.value = bouncerShowMessageModel
258     }
259 
260     override fun setKeyguardAuthenticatedBiometrics(keyguardAuthenticatedBiometrics: Boolean?) {
261         _keyguardAuthenticatedBiometrics.value = keyguardAuthenticatedBiometrics
262     }
263 
264     override suspend fun setKeyguardAuthenticatedPrimaryAuth(userId: Int) {
265         _keyguardAuthenticatedPrimaryAuth.emit(userId)
266     }
267 
268     override suspend fun setUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
269         _userRequestedBouncerWhenAlreadyAuthenticated.emit(userId)
270     }
271 
272     override fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean) {
273         _isBackButtonEnabled.value = isBackButtonEnabled
274     }
275 
276     override fun setLastShownSecurityMode(securityMode: KeyguardSecurityModel.SecurityMode) {
277         _lastShownSecurityMode.value = securityMode
278     }
279 
280     /** Sets up logs for state flows. */
281     private fun setUpLogging() {
282         if (!Build.IS_DEBUGGABLE) {
283             return
284         }
285 
286         primaryBouncerShow
287             .logDiffsForTable(buffer, "", "PrimaryBouncerShow", false)
288             .onEach { Log.d(TAG, "Keyguard Bouncer is ${if (it) "showing" else "hiding."}") }
289             .launchIn(applicationScope)
290         primaryBouncerShowingSoon
291             .logDiffsForTable(buffer, "", "PrimaryBouncerShowingSoon", false)
292             .launchIn(applicationScope)
293         primaryBouncerStartingToHide
294             .logDiffsForTable(buffer, "", "PrimaryBouncerStartingToHide", false)
295             .launchIn(applicationScope)
296         primaryBouncerStartingDisappearAnimation
297             .map { it != null }
298             .logDiffsForTable(buffer, "", "PrimaryBouncerStartingDisappearAnimation", false)
299             .launchIn(applicationScope)
300         primaryBouncerScrimmed
301             .logDiffsForTable(buffer, "", "PrimaryBouncerScrimmed", false)
302             .launchIn(applicationScope)
303         panelExpansionAmount
304             .map { (it * 1000).toInt() }
305             .logDiffsForTable(buffer, "", "PanelExpansionAmountMillis", -1)
306             .launchIn(applicationScope)
307         keyguardPosition
308             .filterNotNull()
309             .map { it.toInt() }
310             .logDiffsForTable(buffer, "", "KeyguardPosition", -1)
311             .launchIn(applicationScope)
312         isBackButtonEnabled
313             .filterNotNull()
314             .logDiffsForTable(buffer, "", "IsBackButtonEnabled", false)
315             .launchIn(applicationScope)
316         showMessage
317             .map { it?.message }
318             .logDiffsForTable(buffer, "", "ShowMessage", null)
319             .launchIn(applicationScope)
320         resourceUpdateRequests
321             .logDiffsForTable(buffer, "", "ResourceUpdateRequests", false)
322             .launchIn(applicationScope)
323         alternateBouncerUIAvailable
324             .logDiffsForTable(buffer, "", "IsAlternateBouncerUIAvailable", false)
325             .launchIn(applicationScope)
326         alternateBouncerVisible
327             .logDiffsForTable(buffer, "", "AlternateBouncerVisible", false)
328             .launchIn(applicationScope)
329         lastShownSecurityMode
330             .map { it.name }
331             .logDiffsForTable(buffer, "", "lastShownSecurityMode", null)
332             .launchIn(applicationScope)
333     }
334 
335     companion object {
336         private const val NOT_VISIBLE = -1L
337         private const val TAG = "KeyguardBouncerRepositoryImpl"
338     }
339 }
340