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