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