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 package com.android.systemui.shade.data.repository 17 18 import android.annotation.SuppressLint 19 import com.android.systemui.dagger.SysUISingleton 20 import com.android.systemui.dagger.qualifiers.Background 21 import javax.inject.Inject 22 import kotlinx.coroutines.CoroutineScope 23 import kotlinx.coroutines.channels.BufferOverflow 24 import kotlinx.coroutines.flow.MutableSharedFlow 25 import kotlinx.coroutines.flow.MutableStateFlow 26 import kotlinx.coroutines.flow.SharedFlow 27 import kotlinx.coroutines.flow.StateFlow 28 import kotlinx.coroutines.flow.asStateFlow 29 import kotlinx.coroutines.launch 30 31 /** Data for the shade, mostly related to expansion of the shade and quick settings. */ 32 interface ShadeRepository { 33 /** 34 * Amount qs has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded. Quick 35 * Settings can be expanded without the full shade expansion. 36 */ 37 @Deprecated("Use ShadeInteractor.qsExpansion instead") val qsExpansion: StateFlow<Float> 38 39 /** Amount shade has expanded with regard to the UDFPS location */ 40 val udfpsTransitionToFullShadeProgress: StateFlow<Float> 41 42 /** 43 * Information about the currently running fling animation, or null if no fling animation is 44 * running. 45 */ 46 val currentFling: SharedFlow<FlingInfo?> 47 48 /** 49 * The amount the lockscreen shade has dragged down by the user, [0-1]. 0 means fully collapsed, 50 * 1 means fully expanded. Value resets to 0 when the user finishes dragging. 51 */ 52 val lockscreenShadeExpansion: StateFlow<Float> 53 54 /** 55 * NotificationPanelViewController.mExpandedFraction as a StateFlow. This nominally represents 56 * the amount the shade has expanded 0-1 like many other flows in this repo, but there are cases 57 * where its value will be 1 and no shade will be rendered, e.g. whenever the keyguard is 58 * visible and when quick settings is expanded. The confusing nature and impending deletion of 59 * this makes it unsuitable for future development, so usage is discouraged. 60 */ 61 @Deprecated("Use ShadeInteractor.shadeExpansion instead") 62 val legacyShadeExpansion: StateFlow<Float> 63 64 /** 65 * NotificationPanelViewController.mTracking as a flow. "Tracking" means that the user is moving 66 * the shade up or down with a pointer. Going forward, this concept will be replaced by checks 67 * for whether a transition was driven by user input instead of whether a pointer is currently 68 * touching the screen, i.e. after the user has lifted their finger to fling the shade, these 69 * values would be different. 70 */ 71 @Deprecated("Use ShadeInteractor instead") val legacyShadeTracking: StateFlow<Boolean> 72 73 /** Specifically tracks the user expanding the shade on the lockscreen only */ 74 @Deprecated("Use ShadeInteractor.isUserInteractingWithShade instead") 75 val legacyLockscreenShadeTracking: MutableStateFlow<Boolean> 76 77 /** 78 * QuickSettingsController.mTracking as a flow. "Tracking" means that the user is moving quick 79 * settings up or down with a pointer. Going forward, this concept will be replaced by checks 80 * for whether a transition was driven by user input instead of whether a pointer is currently 81 * touching the screen, i.e. after the user has lifted their finger to fling the QS, these 82 * values would be different. 83 */ 84 @Deprecated("Use ShadeInteractor instead") val legacyQsTracking: StateFlow<Boolean> 85 86 /** 87 * NotificationPanelViewController.mPanelExpanded as a flow. This value is true whenever the 88 * expansion fraction is greater than zero or NPVC is about to accept an input transfer from the 89 * status bar, home screen, or trackpad. 90 */ 91 @Deprecated("Use ShadeInteractor instead") 92 val legacyExpandedOrAwaitingInputTransfer: StateFlow<Boolean> 93 94 /** 95 * QuickSettingsController.mExpanded as a flow. Indicates that QS is in expanded state: 96 * - single pane shade: expanding shade and then expanding QS 97 * - split shade: just expanding shade (QS are expanded automatically) 98 */ 99 @Deprecated("Use ShadeInteractor instead") val legacyIsQsExpanded: StateFlow<Boolean> 100 101 /** 102 * QuickSettingsController.mExpandImmediate as a flow. Indicates that Quick Settings is being 103 * expanded without first expanding the Shade or Quick Settings is being collapsed without first 104 * collapsing to shade, i.e. expanding with 2-finger swipe or collapsing by flinging from the 105 * bottom of the screen. Replaced by ShadeInteractor.isQsBypassingShade. 106 */ 107 @Deprecated("Use ShadeInteractor.isQsBypassingShade instead") 108 val legacyExpandImmediate: StateFlow<Boolean> 109 110 /** 111 * Whether the shade layout should be wide (true) or narrow (false). 112 * 113 * In a wide layout, notifications and quick settings each take up only half the screen width 114 * (whether they are shown at the same time or not). In a narrow layout, they can each be as 115 * wide as the entire screen. 116 */ 117 val isShadeLayoutWide: StateFlow<Boolean> 118 119 /** True when QS is taking up the entire screen, i.e. fully expanded on a non-unfolded phone. */ 120 @Deprecated("Use ShadeInteractor instead") val legacyQsFullscreen: StateFlow<Boolean> 121 122 /** NPVC.mClosing as a flow. */ 123 @Deprecated("Use ShadeAnimationInteractor instead") val legacyIsClosing: StateFlow<Boolean> 124 125 /** Sets whether the shade layout should be wide (true) or narrow (false). */ setShadeLayoutWidenull126 fun setShadeLayoutWide(isShadeLayoutWide: Boolean) 127 128 /** Sets whether a closing animation is happening. */ 129 @Deprecated("Use ShadeAnimationInteractor instead") fun setLegacyIsClosing(isClosing: Boolean) 130 131 /** */ 132 @Deprecated("Use ShadeInteractor instead") 133 fun setLegacyQsFullscreen(legacyQsFullscreen: Boolean) 134 135 /** 136 * Sets whether Quick Settings is being expanded without first expanding the Shade or Quick 137 * Settings is being collapsed without first collapsing to shade. 138 */ 139 @Deprecated("Use ShadeInteractor instead") 140 fun setLegacyExpandImmediate(legacyExpandImmediate: Boolean) 141 142 /** Sets whether QS is expanded. */ 143 @Deprecated("Use ShadeInteractor instead") 144 fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) 145 146 /** 147 * Sets whether the expansion fraction is greater than zero or NPVC is about to accept an input 148 * transfer from the status bar, home screen, or trackpad. 149 */ 150 @Deprecated("Use ShadeInteractor instead") 151 fun setLegacyExpandedOrAwaitingInputTransfer(legacyExpandedOrAwaitingInputTransfer: Boolean) 152 153 /** Sets whether the user is moving Quick Settings with a pointer */ 154 @Deprecated("Use ShadeInteractor instead") fun setLegacyQsTracking(legacyQsTracking: Boolean) 155 156 /** Sets whether the user is moving the shade with a pointer */ 157 @Deprecated("Use ShadeInteractor instead") fun setLegacyShadeTracking(tracking: Boolean) 158 159 /** Sets whether the user is moving the shade with a pointer, on lockscreen only */ 160 @Deprecated("Use ShadeInteractor instead") 161 fun setLegacyLockscreenShadeTracking(tracking: Boolean) 162 163 /** The amount QS has expanded without notifications */ 164 fun setQsExpansion(qsExpansion: Float) 165 166 fun setUdfpsTransitionToFullShadeProgress(progress: Float) 167 168 /** 169 * Sets the [FlingInfo] of the currently animating fling. If [info] is null, no fling is 170 * animating. 171 */ 172 fun setCurrentFling(info: FlingInfo?) 173 174 /** 175 * Set the amount the shade has dragged down by the user, [0-1]. 0 means fully collapsed, 1 176 * means fully expanded. 177 */ 178 fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float) 179 180 /** 181 * Set the legacy expansion value. This should only be called whenever the value of 182 * NotificationPanelViewController.mExpandedFraction changes or in tests. 183 */ 184 @Deprecated("Should only be called by NPVC and tests") 185 fun setLegacyShadeExpansion(expandedFraction: Float) 186 } 187 188 /** Business logic for shade interactions */ 189 @SysUISingleton 190 class ShadeRepositoryImpl @Inject constructor(@Background val backgroundScope: CoroutineScope) : 191 ShadeRepository { 192 private val _qsExpansion = MutableStateFlow(0f) 193 @Deprecated("Use ShadeInteractor.qsExpansion instead") 194 override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow() 195 196 private val _lockscreenShadeExpansion = MutableStateFlow(0f) 197 override val lockscreenShadeExpansion: StateFlow<Float> = 198 _lockscreenShadeExpansion.asStateFlow() 199 200 private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f) 201 override val udfpsTransitionToFullShadeProgress: StateFlow<Float> = 202 _udfpsTransitionToFullShadeProgress.asStateFlow() 203 204 /** 205 * Must be a SharedFlow, since the fling is by definition an event and dropping it has extreme 206 * consequences in some cases (for example, keyguard uses this to decide when to unlock). 207 */ 208 @SuppressLint("SharedFlowCreation") 209 override val currentFling: MutableSharedFlow<FlingInfo?> = 210 MutableSharedFlow(replay = 2, onBufferOverflow = BufferOverflow.DROP_OLDEST) 211 212 private val _legacyShadeExpansion = MutableStateFlow(0f) 213 @Deprecated("Use ShadeInteractor.shadeExpansion instead") 214 override val legacyShadeExpansion: StateFlow<Float> = _legacyShadeExpansion.asStateFlow() 215 216 private val _legacyShadeTracking = MutableStateFlow(false) 217 @Deprecated("Use ShadeInteractor instead") 218 override val legacyShadeTracking: StateFlow<Boolean> = _legacyShadeTracking.asStateFlow() 219 220 @Deprecated("Use ShadeInteractor.isUserInteractingWithShade instead") 221 override val legacyLockscreenShadeTracking = MutableStateFlow(false) 222 223 private val _legacyQsTracking = MutableStateFlow(false) 224 @Deprecated("Use ShadeInteractor instead") 225 override val legacyQsTracking: StateFlow<Boolean> = _legacyQsTracking.asStateFlow() 226 227 private val _legacyExpandedOrAwaitingInputTransfer = MutableStateFlow(false) 228 @Deprecated("Use ShadeInteractor instead") 229 override val legacyExpandedOrAwaitingInputTransfer: StateFlow<Boolean> = 230 _legacyExpandedOrAwaitingInputTransfer.asStateFlow() 231 232 private val _legacyIsQsExpanded = MutableStateFlow(false) 233 @Deprecated("Use ShadeInteractor instead") 234 override val legacyIsQsExpanded: StateFlow<Boolean> = _legacyIsQsExpanded.asStateFlow() 235 236 private val _legacyExpandImmediate = MutableStateFlow(false) 237 @Deprecated("Use ShadeInteractor instead") 238 override val legacyExpandImmediate: StateFlow<Boolean> = _legacyExpandImmediate.asStateFlow() 239 240 private val _legacyQsFullscreen = MutableStateFlow(false) 241 @Deprecated("Use ShadeInteractor instead") 242 override val legacyQsFullscreen: StateFlow<Boolean> = _legacyQsFullscreen.asStateFlow() 243 244 private val _isShadeLayoutWide = MutableStateFlow(false) 245 override val isShadeLayoutWide: StateFlow<Boolean> = _isShadeLayoutWide.asStateFlow() 246 247 override fun setShadeLayoutWide(isShadeLayoutWide: Boolean) { 248 _isShadeLayoutWide.value = isShadeLayoutWide 249 } 250 251 @Deprecated("Use ShadeInteractor instead") 252 override fun setLegacyQsFullscreen(legacyQsFullscreen: Boolean) { 253 _legacyQsFullscreen.value = legacyQsFullscreen 254 } 255 256 @Deprecated("Use ShadeInteractor instead") 257 override fun setLegacyExpandImmediate(legacyExpandImmediate: Boolean) { 258 _legacyExpandImmediate.value = legacyExpandImmediate 259 } 260 261 @Deprecated("Use ShadeInteractor instead") 262 override fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) { 263 _legacyIsQsExpanded.value = legacyIsQsExpanded 264 } 265 266 @Deprecated("Use ShadeInteractor instead") 267 override fun setLegacyExpandedOrAwaitingInputTransfer( 268 legacyExpandedOrAwaitingInputTransfer: Boolean 269 ) { 270 _legacyExpandedOrAwaitingInputTransfer.value = legacyExpandedOrAwaitingInputTransfer 271 } 272 273 @Deprecated("Should only be called by NPVC and tests") 274 override fun setLegacyQsTracking(legacyQsTracking: Boolean) { 275 _legacyQsTracking.value = legacyQsTracking 276 } 277 278 @Deprecated("Should only be called by NPVC and tests") 279 override fun setLegacyShadeTracking(tracking: Boolean) { 280 _legacyShadeTracking.value = tracking 281 } 282 283 private val _legacyIsClosing = MutableStateFlow(false) 284 @Deprecated("Use ShadeInteractor instead") 285 override val legacyIsClosing: StateFlow<Boolean> = _legacyIsClosing.asStateFlow() 286 287 @Deprecated("Use ShadeInteractor instead") 288 override fun setLegacyIsClosing(isClosing: Boolean) { 289 _legacyIsClosing.value = isClosing 290 } 291 292 @Deprecated("Should only be called by NPVC and tests") 293 override fun setLegacyLockscreenShadeTracking(tracking: Boolean) { 294 legacyLockscreenShadeTracking.value = tracking 295 } 296 297 override fun setQsExpansion(qsExpansion: Float) { 298 _qsExpansion.value = qsExpansion 299 } 300 301 override fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float) { 302 _lockscreenShadeExpansion.value = lockscreenShadeExpansion 303 } 304 305 override fun setUdfpsTransitionToFullShadeProgress(progress: Float) { 306 _udfpsTransitionToFullShadeProgress.value = progress 307 } 308 309 override fun setCurrentFling(info: FlingInfo?) { 310 backgroundScope.launch { currentFling.emit(info) } 311 } 312 313 @Deprecated("Should only be called by NPVC and tests") 314 override fun setLegacyShadeExpansion(expandedFraction: Float) { 315 _legacyShadeExpansion.value = expandedFraction 316 } 317 318 companion object { 319 private const val TAG = "ShadeRepository" 320 } 321 } 322