1 /* 2 * Copyright (C) 2023 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 17 18 import android.view.MotionEvent 19 import android.view.ViewGroup 20 import android.view.ViewTreeObserver 21 import com.android.systemui.keyguard.shared.model.WakefulnessModel 22 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow 23 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController 24 import com.android.systemui.statusbar.phone.KeyguardStatusBarView 25 import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController 26 import java.util.function.Consumer 27 28 /** 29 * Controller for the top level shade view 30 * 31 * @see NotificationPanelViewController 32 */ 33 interface ShadeViewController { 34 /** Expand the shade either animated or instantly. */ 35 fun expand(animate: Boolean) 36 37 /** Animates to an expanded shade with QS expanded. If the shade starts expanded, expands QS. */ 38 fun expandToQs() 39 40 /** 41 * Expand shade so that notifications are visible. Non-split shade: just expanding shade or 42 * collapsing QS when they're expanded. Split shade: only expanding shade, notifications are 43 * always visible 44 * 45 * Called when `adb shell cmd statusbar expand-notifications` is executed. 46 */ 47 fun expandToNotifications() 48 49 /** Returns whether the shade is expanding or collapsing itself or quick settings. */ 50 val isExpandingOrCollapsing: Boolean 51 52 /** 53 * Returns whether the shade height is greater than zero (i.e. partially or fully expanded), 54 * there is a HUN, the shade is animating, or the shade is instantly expanding. 55 */ 56 val isExpanded: Boolean 57 58 /** 59 * Returns whether the shade height is greater than zero or the shade is expecting a synthesized 60 * down event. 61 */ 62 val isPanelExpanded: Boolean 63 64 /** Returns whether the shade is fully expanded in either QS or QQS. */ 65 val isShadeFullyExpanded: Boolean 66 67 /** 68 * Animates the collapse of a shade with the given delay and the default duration divided by 69 * speedUpFactor. 70 */ 71 fun collapse(delayed: Boolean, speedUpFactor: Float) 72 73 /** Collapses the shade. */ 74 fun collapse(animate: Boolean, delayed: Boolean, speedUpFactor: Float) 75 76 /** Collapses the shade with an animation duration in milliseconds. */ 77 fun collapseWithDuration(animationDuration: Int) 78 79 /** Collapses the shade instantly without animation. */ 80 fun instantCollapse() 81 82 /** 83 * Animate QS collapse by flinging it. If QS is expanded, it will collapse into QQS and stop. If 84 * in split shade, it will collapse the whole shade. 85 * 86 * @param fullyCollapse Do not stop when QS becomes QQS. Fling until QS isn't visible anymore. 87 */ 88 fun animateCollapseQs(fullyCollapse: Boolean) 89 90 /** Returns whether the shade can be collapsed. */ 91 fun canBeCollapsed(): Boolean 92 93 /** Returns whether the shade is in the process of collapsing. */ 94 val isCollapsing: Boolean 95 96 /** Returns whether shade's height is zero. */ 97 val isFullyCollapsed: Boolean 98 99 /** Returns whether the shade is tracking touches for expand/collapse of the shade or QS. */ 100 val isTracking: Boolean 101 102 /** Returns whether the shade's top level view is enabled. */ 103 val isViewEnabled: Boolean 104 105 /** Sets a listener to be notified when the shade starts opening or finishes closing. */ 106 fun setOpenCloseListener(openCloseListener: OpenCloseListener) 107 108 /** Returns whether status bar icons should be hidden when the shade is expanded. */ 109 fun shouldHideStatusBarIconsWhenExpanded(): Boolean 110 111 /** 112 * Do not let the user drag the shade up and down for the current touch session. This is 113 * necessary to avoid shade expansion while/after the bouncer is dismissed. 114 */ 115 fun blockExpansionForCurrentTouch() 116 117 /** Sets a listener to be notified when touch tracking begins. */ 118 fun setTrackingStartedListener(trackingStartedListener: TrackingStartedListener) 119 120 /** 121 * Disables the shade header. 122 * 123 * @see ShadeHeaderController.disable 124 */ 125 fun disableHeader(state1: Int, state2: Int, animated: Boolean) 126 127 /** If the latency tracker is enabled, begins tracking expand latency. */ 128 fun startExpandLatencyTracking() 129 130 /** Called before animating Keyguard dismissal, i.e. the animation dismissing the bouncer. */ 131 fun startBouncerPreHideAnimation() 132 133 /** Called once every minute while dozing. */ 134 fun dozeTimeTick() 135 136 /** Close guts, notification menus, and QS. Set scroll and overscroll to 0. */ 137 fun resetViews(animate: Boolean) 138 139 /** Returns the StatusBarState. */ 140 val barState: Int 141 142 /** Sets the amount of progress in the status bar launch animation. */ 143 fun applyLaunchAnimationProgress(linearProgress: Float) 144 145 /** 146 * Close the keyguard user switcher if it is open and capable of closing. 147 * 148 * Has no effect if user switcher isn't supported, if the user switcher is already closed, or if 149 * the user switcher uses "simple" mode. The simple user switcher cannot be closed. 150 * 151 * @return true if the keyguard user switcher was open, and is now closed 152 */ 153 fun closeUserSwitcherIfOpen(): Boolean 154 155 /** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */ 156 fun onBackPressed() 157 158 /** Sets whether the status bar launch animation is currently running. */ 159 fun setIsLaunchAnimationRunning(running: Boolean) 160 161 /** Sets the alpha value of the shade to a value between 0 and 255. */ 162 fun setAlpha(alpha: Int, animate: Boolean) 163 164 /** 165 * Sets the runnable to run after the alpha change animation completes. 166 * 167 * @see .setAlpha 168 */ 169 fun setAlphaChangeAnimationEndAction(r: Runnable) 170 171 /** Sets whether the screen has temporarily woken up to display notifications. */ 172 fun setPulsing(pulsing: Boolean) 173 174 /** Sets Qs ScrimEnabled and updates QS state. */ 175 fun setQsScrimEnabled(qsScrimEnabled: Boolean) 176 177 /** Sets the top spacing for the ambient indicator. */ 178 fun setAmbientIndicationTop(ambientIndicationTop: Int, ambientTextVisible: Boolean) 179 180 /** Updates notification panel-specific flags on [SysUiState]. */ 181 fun updateSystemUiStateFlags() 182 183 /** Ensures that the touchable region is updated. */ 184 fun updateTouchableRegion() 185 186 /** Adds a global layout listener. */ 187 fun addOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener) 188 189 /** Removes a global layout listener. */ 190 fun removeOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener) 191 192 /** Posts the given runnable to the view. */ 193 fun postToView(action: Runnable): Boolean 194 195 // ******* Begin Keyguard Section ********* 196 /** Animate to expanded shade after a delay in ms. Used for lockscreen to shade transition. */ 197 fun transitionToExpandedShade(delay: Long) 198 199 /** 200 * Returns whether the unlock hint animation is running. The unlock hint animation is when the 201 * user taps the lock screen, causing the contents of the lock screen visually bounce. 202 */ 203 val isUnlockHintRunning: Boolean 204 205 /** @see ViewGroupFadeHelper.reset */ 206 fun resetViewGroupFade() 207 208 /** 209 * Set the alpha and translationY of the keyguard elements which only show on the lockscreen, 210 * but not in shade locked / shade. This is used when dragging down to the full shade. 211 */ 212 fun setKeyguardTransitionProgress(keyguardAlpha: Float, keyguardTranslationY: Int) 213 214 /** Sets the overstretch amount in raw pixels when dragging down. */ 215 fun setOverStretchAmount(amount: Float) 216 217 /** 218 * Sets the alpha value to be set on the keyguard status bar. 219 * 220 * @param alpha value between 0 and 1. -1 if the value is to be reset. 221 */ 222 fun setKeyguardStatusBarAlpha(alpha: Float) 223 224 /** 225 * Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the 226 * screen off animation controller in order to animate in AOD without "actually" fully switching 227 * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the 228 * change. 229 */ 230 fun showAodUi() 231 232 /** 233 * This method should not be used anymore, you should probably use [.isShadeFullyOpen] instead. 234 * It was overused as indicating if shade is open or we're on keyguard/AOD. Moving forward we 235 * should be explicit about the what state we're checking. 236 * 237 * @return if panel is covering the screen, which means we're in expanded shade or keyguard/AOD 238 */ 239 @Deprecated( 240 "depends on the state you check, use {@link #isShadeFullyExpanded()},\n" + 241 "{@link #isOnAod()}, {@link #isOnKeyguard()} instead." 242 ) 243 fun isFullyExpanded(): Boolean 244 245 /** Sends an external (e.g. Status Bar) touch event to the Shade touch handler. */ 246 fun handleExternalTouch(event: MotionEvent): Boolean 247 248 /** Starts tracking a shade expansion gesture that originated from the status bar. */ 249 fun startTrackingExpansionFromStatusBar() 250 251 /** 252 * Performs haptic feedback from a view with a haptic feedback constant. 253 * 254 * The implementation of this method should use the [android.view.View.performHapticFeedback] 255 * method with the provided constant. 256 * 257 * @param[constant] One of [android.view.HapticFeedbackConstants] 258 */ 259 fun performHapticFeedback(constant: Int) 260 261 // ******* End Keyguard Section ********* 262 263 /** Returns the ShadeHeadsUpTracker. */ 264 val shadeHeadsUpTracker: ShadeHeadsUpTracker 265 266 /** Returns the ShadeFoldAnimator. */ 267 val shadeFoldAnimator: ShadeFoldAnimator 268 269 companion object { 270 /** 271 * Returns a multiplicative factor to use when determining the falsing threshold for touches 272 * on the shade. The factor will be larger when the device is waking up due to a touch or 273 * gesture. 274 */ 275 @JvmStatic 276 fun getFalsingThresholdFactor(wakefulness: WakefulnessModel): Float { 277 return if (wakefulness.isDeviceInteractiveFromTapOrGesture()) 1.5f else 1.0f 278 } 279 280 const val WAKEUP_ANIMATION_DELAY_MS = 250 281 const val FLING_MAX_LENGTH_SECONDS = 0.6f 282 const val FLING_SPEED_UP_FACTOR = 0.6f 283 const val FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f 284 const val FLING_CLOSING_SPEED_UP_FACTOR = 0.6f 285 286 /** Fling expanding QS. */ 287 const val FLING_EXPAND = 0 288 289 /** Fling collapsing QS, potentially stopping when QS becomes QQS. */ 290 const val FLING_COLLAPSE = 1 291 292 /** Fling until QS is completely hidden. */ 293 const val FLING_HIDE = 2 294 } 295 } 296 297 /** Manages listeners for when users begin expanding the shade from a HUN. */ 298 interface ShadeHeadsUpTracker { 299 /** Add a listener for when the user starts expanding the shade from a HUN. */ 300 fun addTrackingHeadsUpListener(listener: Consumer<ExpandableNotificationRow>) 301 302 /** Remove a listener for when the user starts expanding the shade from a HUN. */ 303 fun removeTrackingHeadsUpListener(listener: Consumer<ExpandableNotificationRow>) 304 305 /** Set the controller for the appearance of HUNs in the icon area and the header itself. */ 306 fun setHeadsUpAppearanceController(headsUpAppearanceController: HeadsUpAppearanceController?) 307 308 /** The notification row that was touched to initiate shade expansion. */ 309 val trackedHeadsUpNotification: ExpandableNotificationRow? 310 } 311 312 /** Handles the lifecycle of the shade's animation that happens when folding a foldable. */ 313 interface ShadeFoldAnimator { 314 /** Updates the views to the initial state for the fold to AOD animation. */ 315 fun prepareFoldToAodAnimation() 316 317 /** 318 * Starts fold to AOD animation. 319 * 320 * @param startAction invoked when the animation starts. 321 * @param endAction invoked when the animation finishes, also if it was cancelled. 322 * @param cancelAction invoked when the animation is cancelled, before endAction. 323 */ 324 fun startFoldToAodAnimation(startAction: Runnable, endAction: Runnable, cancelAction: Runnable) 325 326 /** Cancels fold to AOD transition and resets view state. */ 327 fun cancelFoldToAodAnimation() 328 329 /** Returns the main view of the shade. */ 330 val view: ViewGroup? 331 } 332 333 /** 334 * An interface that provides the current state of the notification panel and related views, which 335 * is needed to calculate [KeyguardStatusBarView]'s state in [KeyguardStatusBarViewController]. 336 */ 337 interface ShadeViewStateProvider { 338 /** Returns the expanded height of the panel view. */ 339 val panelViewExpandedHeight: Float 340 341 /** 342 * Returns true if heads up should be visible. 343 * 344 * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into 345 * [KeyguardStatusBarViewController] and remove this method. 346 */ 347 fun shouldHeadsUpBeVisible(): Boolean 348 349 /** Return the fraction of the shade that's expanded, when in lockscreen. */ 350 val lockscreenShadeDragProgress: Float 351 } 352 353 /** Listens for when touch tracking begins. */ 354 interface TrackingStartedListener { 355 fun onTrackingStarted() 356 } 357 358 /** Listens for when shade begins opening or finishes closing. */ 359 interface OpenCloseListener { 360 /** Called when the shade finishes closing. */ 361 fun onClosingFinished() 362 363 /** Called when the shade starts opening. */ 364 fun onOpenStarted() 365 } 366