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.data.repository 18 19 import android.os.Build 20 import android.util.Log 21 import com.android.keyguard.ViewMediatorCallback 22 import com.android.systemui.dagger.SysUISingleton 23 import com.android.systemui.dagger.qualifiers.Application 24 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN 25 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel 26 import com.android.systemui.log.dagger.BouncerLog 27 import com.android.systemui.log.table.TableLogBuffer 28 import com.android.systemui.log.table.logDiffsForTable 29 import com.android.systemui.util.time.SystemClock 30 import javax.inject.Inject 31 import kotlinx.coroutines.CoroutineScope 32 import kotlinx.coroutines.flow.MutableStateFlow 33 import kotlinx.coroutines.flow.StateFlow 34 import kotlinx.coroutines.flow.asStateFlow 35 import kotlinx.coroutines.flow.filterNotNull 36 import kotlinx.coroutines.flow.launchIn 37 import kotlinx.coroutines.flow.map 38 import kotlinx.coroutines.flow.onEach 39 40 /** 41 * Encapsulates app state for the lock screen primary and alternate bouncer. 42 * 43 * Make sure to add newly added flows to the logger. 44 */ 45 interface KeyguardBouncerRepository { 46 /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */ 47 val primaryBouncerShow: StateFlow<Boolean> 48 val primaryBouncerShowingSoon: StateFlow<Boolean> 49 val primaryBouncerStartingToHide: StateFlow<Boolean> 50 val primaryBouncerStartingDisappearAnimation: StateFlow<Runnable?> 51 /** Determines if we want to instantaneously show the primary bouncer instead of translating. */ 52 val primaryBouncerScrimmed: StateFlow<Boolean> 53 /** 54 * Set how much of the notification panel is showing on the screen. 55 * 56 * ``` 57 * 0f = panel fully hidden = bouncer fully showing 58 * 1f = panel fully showing = bouncer fully hidden 59 * ``` 60 */ 61 val panelExpansionAmount: StateFlow<Float> 62 val keyguardPosition: StateFlow<Float> 63 val isBackButtonEnabled: StateFlow<Boolean?> 64 /** Determines if user is already unlocked */ 65 val keyguardAuthenticated: StateFlow<Boolean?> 66 val showMessage: StateFlow<BouncerShowMessageModel?> 67 val resourceUpdateRequests: StateFlow<Boolean> 68 val bouncerPromptReason: Int 69 val bouncerErrorMessage: CharSequence? 70 val alternateBouncerVisible: StateFlow<Boolean> 71 val alternateBouncerUIAvailable: StateFlow<Boolean> 72 val sideFpsShowing: StateFlow<Boolean> 73 74 var lastAlternateBouncerVisibleTime: Long 75 setPrimaryScrimmednull76 fun setPrimaryScrimmed(isScrimmed: Boolean) 77 78 fun setPrimaryShow(isShowing: Boolean) 79 80 fun setPrimaryShowingSoon(showingSoon: Boolean) 81 82 fun setPrimaryStartingToHide(startingToHide: Boolean) 83 84 fun setPrimaryStartDisappearAnimation(runnable: Runnable?) 85 86 fun setPanelExpansion(panelExpansion: Float) 87 88 fun setKeyguardPosition(keyguardPosition: Float) 89 90 fun setResourceUpdateRequests(willUpdateResources: Boolean) 91 92 fun setShowMessage(bouncerShowMessageModel: BouncerShowMessageModel?) 93 94 fun setKeyguardAuthenticated(keyguardAuthenticated: Boolean?) 95 96 fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean) 97 98 fun setAlternateVisible(isVisible: Boolean) 99 100 fun setAlternateBouncerUIAvailable(isAvailable: Boolean) 101 102 fun setSideFpsShowing(isShowing: Boolean) 103 } 104 105 @SysUISingleton 106 class KeyguardBouncerRepositoryImpl 107 @Inject 108 constructor( 109 private val viewMediatorCallback: ViewMediatorCallback, 110 private val clock: SystemClock, 111 @Application private val applicationScope: CoroutineScope, 112 @BouncerLog private val buffer: TableLogBuffer, 113 ) : KeyguardBouncerRepository { 114 /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */ 115 private val _primaryBouncerShow = MutableStateFlow(false) 116 override val primaryBouncerShow = _primaryBouncerShow.asStateFlow() 117 private val _primaryBouncerShowingSoon = MutableStateFlow(false) 118 override val primaryBouncerShowingSoon = _primaryBouncerShowingSoon.asStateFlow() 119 private val _primaryBouncerStartingToHide = MutableStateFlow(false) 120 override val primaryBouncerStartingToHide = _primaryBouncerStartingToHide.asStateFlow() 121 private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null) 122 override val primaryBouncerStartingDisappearAnimation = 123 _primaryBouncerDisappearAnimation.asStateFlow() 124 /** Determines if we want to instantaneously show the primary bouncer instead of translating. */ 125 private val _primaryBouncerScrimmed = MutableStateFlow(false) 126 override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow() 127 /** 128 * Set how much of the notification panel is showing on the screen. 129 * 130 * ``` 131 * 0f = panel fully hidden = bouncer fully showing 132 * 1f = panel fully showing = bouncer fully hidden 133 * ``` 134 */ 135 private val _panelExpansionAmount = MutableStateFlow(EXPANSION_HIDDEN) 136 override val panelExpansionAmount = _panelExpansionAmount.asStateFlow() 137 private val _keyguardPosition = MutableStateFlow(0f) 138 override val keyguardPosition = _keyguardPosition.asStateFlow() 139 private val _isBackButtonEnabled = MutableStateFlow<Boolean?>(null) 140 override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow() 141 private val _keyguardAuthenticated = MutableStateFlow<Boolean?>(null) 142 /** Determines if user is already unlocked */ 143 override val keyguardAuthenticated = _keyguardAuthenticated.asStateFlow() 144 private val _showMessage = MutableStateFlow<BouncerShowMessageModel?>(null) 145 override val showMessage = _showMessage.asStateFlow() 146 private val _resourceUpdateRequests = MutableStateFlow(false) 147 override val resourceUpdateRequests = _resourceUpdateRequests.asStateFlow() 148 override val bouncerPromptReason: Int 149 get() = viewMediatorCallback.bouncerPromptReason 150 override val bouncerErrorMessage: CharSequence? 151 get() = viewMediatorCallback.consumeCustomMessage() 152 153 /** Values associated with the AlternateBouncer */ 154 private val _alternateBouncerVisible = MutableStateFlow(false) 155 override val alternateBouncerVisible = _alternateBouncerVisible.asStateFlow() 156 override var lastAlternateBouncerVisibleTime: Long = NOT_VISIBLE 157 private val _alternateBouncerUIAvailable = MutableStateFlow(false) 158 override val alternateBouncerUIAvailable: StateFlow<Boolean> = 159 _alternateBouncerUIAvailable.asStateFlow() 160 private val _sideFpsShowing = MutableStateFlow(false) 161 override val sideFpsShowing: StateFlow<Boolean> = _sideFpsShowing.asStateFlow() 162 163 init { 164 setUpLogging() 165 } 166 167 override fun setPrimaryScrimmed(isScrimmed: Boolean) { 168 _primaryBouncerScrimmed.value = isScrimmed 169 } 170 171 override fun setAlternateVisible(isVisible: Boolean) { 172 if (isVisible && !_alternateBouncerVisible.value) { 173 lastAlternateBouncerVisibleTime = clock.uptimeMillis() 174 } else if (!isVisible) { 175 lastAlternateBouncerVisibleTime = NOT_VISIBLE 176 } 177 _alternateBouncerVisible.value = isVisible 178 } 179 180 override fun setAlternateBouncerUIAvailable(isAvailable: Boolean) { 181 _alternateBouncerUIAvailable.value = isAvailable 182 } 183 184 override fun setPrimaryShow(isShowing: Boolean) { 185 _primaryBouncerShow.value = isShowing 186 } 187 188 override fun setPrimaryShowingSoon(showingSoon: Boolean) { 189 _primaryBouncerShowingSoon.value = showingSoon 190 } 191 192 override fun setPrimaryStartingToHide(startingToHide: Boolean) { 193 _primaryBouncerStartingToHide.value = startingToHide 194 } 195 196 override fun setPrimaryStartDisappearAnimation(runnable: Runnable?) { 197 _primaryBouncerDisappearAnimation.value = runnable 198 } 199 200 override fun setPanelExpansion(panelExpansion: Float) { 201 _panelExpansionAmount.value = panelExpansion 202 } 203 204 override fun setKeyguardPosition(keyguardPosition: Float) { 205 _keyguardPosition.value = keyguardPosition 206 } 207 208 override fun setResourceUpdateRequests(willUpdateResources: Boolean) { 209 _resourceUpdateRequests.value = willUpdateResources 210 } 211 212 override fun setShowMessage(bouncerShowMessageModel: BouncerShowMessageModel?) { 213 _showMessage.value = bouncerShowMessageModel 214 } 215 216 override fun setKeyguardAuthenticated(keyguardAuthenticated: Boolean?) { 217 _keyguardAuthenticated.value = keyguardAuthenticated 218 } 219 220 override fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean) { 221 _isBackButtonEnabled.value = isBackButtonEnabled 222 } 223 224 override fun setSideFpsShowing(isShowing: Boolean) { 225 _sideFpsShowing.value = isShowing 226 } 227 228 /** Sets up logs for state flows. */ 229 private fun setUpLogging() { 230 if (!Build.IS_DEBUGGABLE) { 231 return 232 } 233 234 primaryBouncerShow 235 .logDiffsForTable(buffer, "", "PrimaryBouncerShow", false) 236 .onEach { Log.d(TAG, "Keyguard Bouncer is ${if (it) "showing" else "hiding."}") } 237 .launchIn(applicationScope) 238 primaryBouncerShowingSoon 239 .logDiffsForTable(buffer, "", "PrimaryBouncerShowingSoon", false) 240 .launchIn(applicationScope) 241 primaryBouncerStartingToHide 242 .logDiffsForTable(buffer, "", "PrimaryBouncerStartingToHide", false) 243 .launchIn(applicationScope) 244 primaryBouncerStartingDisappearAnimation 245 .map { it != null } 246 .logDiffsForTable(buffer, "", "PrimaryBouncerStartingDisappearAnimation", false) 247 .launchIn(applicationScope) 248 primaryBouncerScrimmed 249 .logDiffsForTable(buffer, "", "PrimaryBouncerScrimmed", false) 250 .launchIn(applicationScope) 251 panelExpansionAmount 252 .map { (it * 1000).toInt() } 253 .logDiffsForTable(buffer, "", "PanelExpansionAmountMillis", -1) 254 .launchIn(applicationScope) 255 keyguardPosition 256 .map { it.toInt() } 257 .logDiffsForTable(buffer, "", "KeyguardPosition", -1) 258 .launchIn(applicationScope) 259 isBackButtonEnabled 260 .filterNotNull() 261 .logDiffsForTable(buffer, "", "IsBackButtonEnabled", false) 262 .launchIn(applicationScope) 263 showMessage 264 .map { it?.message } 265 .logDiffsForTable(buffer, "", "ShowMessage", null) 266 .launchIn(applicationScope) 267 resourceUpdateRequests 268 .logDiffsForTable(buffer, "", "ResourceUpdateRequests", false) 269 .launchIn(applicationScope) 270 alternateBouncerUIAvailable 271 .logDiffsForTable(buffer, "", "IsAlternateBouncerUIAvailable", false) 272 .launchIn(applicationScope) 273 sideFpsShowing 274 .logDiffsForTable(buffer, "", "isSideFpsShowing", false) 275 .launchIn(applicationScope) 276 } 277 278 companion object { 279 private const val NOT_VISIBLE = -1L 280 private const val TAG = "KeyguardBouncerRepositoryImpl" 281 } 282 } 283