1 /* 2 * Copyright (C) 2019 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.shade; 18 19 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; 20 import static android.view.View.INVISIBLE; 21 import static android.view.View.VISIBLE; 22 23 import static androidx.constraintlayout.widget.ConstraintSet.END; 24 import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID; 25 26 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION; 27 import static com.android.keyguard.KeyguardClockSwitch.LARGE; 28 import static com.android.keyguard.KeyguardClockSwitch.SMALL; 29 import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE; 30 import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE; 31 import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK; 32 import static com.android.systemui.classifier.Classifier.GENERIC; 33 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; 34 import static com.android.systemui.classifier.Classifier.UNLOCK; 35 import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED; 36 import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN; 37 import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPENING; 38 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; 39 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE; 40 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; 41 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; 42 import static com.android.systemui.statusbar.StatusBarState.SHADE; 43 import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; 44 import static com.android.systemui.statusbar.VibratorHelper.TOUCH_VIBRATION_ATTRIBUTES; 45 import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FOLD_TO_AOD; 46 import static com.android.systemui.util.DumpUtilsKt.asIndenting; 47 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; 48 49 import static java.lang.Float.isNaN; 50 51 import android.animation.Animator; 52 import android.animation.AnimatorListenerAdapter; 53 import android.animation.ValueAnimator; 54 import android.annotation.NonNull; 55 import android.annotation.Nullable; 56 import android.app.StatusBarManager; 57 import android.content.ContentResolver; 58 import android.content.res.Resources; 59 import android.database.ContentObserver; 60 import android.graphics.Color; 61 import android.graphics.Insets; 62 import android.graphics.Rect; 63 import android.graphics.Region; 64 import android.hardware.biometrics.SensorLocationInternal; 65 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 66 import android.os.Bundle; 67 import android.os.Handler; 68 import android.os.PowerManager; 69 import android.os.Process; 70 import android.os.Trace; 71 import android.os.UserManager; 72 import android.os.VibrationEffect; 73 import android.provider.Settings; 74 import android.transition.ChangeBounds; 75 import android.transition.Transition; 76 import android.transition.TransitionListenerAdapter; 77 import android.transition.TransitionManager; 78 import android.transition.TransitionSet; 79 import android.transition.TransitionValues; 80 import android.util.IndentingPrintWriter; 81 import android.util.Log; 82 import android.util.MathUtils; 83 import android.view.InputDevice; 84 import android.view.LayoutInflater; 85 import android.view.MotionEvent; 86 import android.view.VelocityTracker; 87 import android.view.View; 88 import android.view.View.AccessibilityDelegate; 89 import android.view.ViewConfiguration; 90 import android.view.ViewGroup; 91 import android.view.ViewPropertyAnimator; 92 import android.view.ViewStub; 93 import android.view.ViewTreeObserver; 94 import android.view.WindowInsets; 95 import android.view.accessibility.AccessibilityEvent; 96 import android.view.accessibility.AccessibilityManager; 97 import android.view.accessibility.AccessibilityNodeInfo; 98 import android.view.animation.Interpolator; 99 import android.widget.FrameLayout; 100 101 import androidx.constraintlayout.widget.ConstraintSet; 102 103 import com.android.internal.annotations.VisibleForTesting; 104 import com.android.internal.jank.InteractionJankMonitor; 105 import com.android.internal.logging.MetricsLogger; 106 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 107 import com.android.internal.policy.SystemBarUtils; 108 import com.android.internal.util.LatencyTracker; 109 import com.android.keyguard.ActiveUnlockConfig; 110 import com.android.keyguard.FaceAuthApiRequestReason; 111 import com.android.keyguard.KeyguardClockSwitch.ClockSize; 112 import com.android.keyguard.KeyguardStatusView; 113 import com.android.keyguard.KeyguardStatusViewController; 114 import com.android.keyguard.KeyguardUnfoldTransition; 115 import com.android.keyguard.KeyguardUpdateMonitor; 116 import com.android.keyguard.LockIconViewController; 117 import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; 118 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; 119 import com.android.keyguard.dagger.KeyguardStatusViewComponent; 120 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; 121 import com.android.systemui.DejankUtils; 122 import com.android.systemui.Dumpable; 123 import com.android.systemui.Gefingerpoken; 124 import com.android.systemui.R; 125 import com.android.systemui.animation.ActivityLaunchAnimator; 126 import com.android.systemui.animation.Interpolators; 127 import com.android.systemui.animation.LaunchAnimator; 128 import com.android.systemui.biometrics.AuthController; 129 import com.android.systemui.classifier.Classifier; 130 import com.android.systemui.classifier.FalsingCollector; 131 import com.android.systemui.dagger.qualifiers.DisplayId; 132 import com.android.systemui.dagger.qualifiers.Main; 133 import com.android.systemui.doze.DozeLog; 134 import com.android.systemui.dump.DumpManager; 135 import com.android.systemui.dump.DumpsysTableLogger; 136 import com.android.systemui.flags.FeatureFlags; 137 import com.android.systemui.flags.Flags; 138 import com.android.systemui.fragments.FragmentService; 139 import com.android.systemui.keyguard.KeyguardUnlockAnimationController; 140 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; 141 import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor; 142 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; 143 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; 144 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants; 145 import com.android.systemui.keyguard.shared.model.TransitionState; 146 import com.android.systemui.keyguard.shared.model.TransitionStep; 147 import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder; 148 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; 149 import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel; 150 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel; 151 import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel; 152 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel; 153 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel; 154 import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel; 155 import com.android.systemui.media.controls.pipeline.MediaDataManager; 156 import com.android.systemui.media.controls.ui.KeyguardMediaController; 157 import com.android.systemui.media.controls.ui.MediaHierarchyManager; 158 import com.android.systemui.model.SysUiState; 159 import com.android.systemui.navigationbar.NavigationBarController; 160 import com.android.systemui.navigationbar.NavigationBarView; 161 import com.android.systemui.navigationbar.NavigationModeController; 162 import com.android.systemui.plugins.ClockAnimations; 163 import com.android.systemui.plugins.FalsingManager; 164 import com.android.systemui.plugins.FalsingManager.FalsingTapListener; 165 import com.android.systemui.plugins.qs.QS; 166 import com.android.systemui.plugins.statusbar.StatusBarStateController; 167 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; 168 import com.android.systemui.shade.transition.ShadeTransitionController; 169 import com.android.systemui.shared.system.QuickStepContract; 170 import com.android.systemui.statusbar.CommandQueue; 171 import com.android.systemui.statusbar.GestureRecorder; 172 import com.android.systemui.statusbar.KeyguardIndicationController; 173 import com.android.systemui.statusbar.LockscreenShadeTransitionController; 174 import com.android.systemui.statusbar.NotificationShadeDepthController; 175 import com.android.systemui.statusbar.NotificationShadeWindowController; 176 import com.android.systemui.statusbar.NotificationShelfController; 177 import com.android.systemui.statusbar.PulseExpansionHandler; 178 import com.android.systemui.statusbar.RemoteInputController; 179 import com.android.systemui.statusbar.StatusBarState; 180 import com.android.systemui.statusbar.SysuiStatusBarStateController; 181 import com.android.systemui.statusbar.VibratorHelper; 182 import com.android.systemui.statusbar.notification.AnimatableProperty; 183 import com.android.systemui.statusbar.notification.ConversationNotificationManager; 184 import com.android.systemui.statusbar.notification.DynamicPrivacyController; 185 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; 186 import com.android.systemui.statusbar.notification.PropertyAnimator; 187 import com.android.systemui.statusbar.notification.ViewGroupFadeHelper; 188 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 189 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; 190 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; 191 import com.android.systemui.statusbar.notification.row.ExpandableView; 192 import com.android.systemui.statusbar.notification.row.NotificationGutsManager; 193 import com.android.systemui.statusbar.notification.stack.AmbientState; 194 import com.android.systemui.statusbar.notification.stack.AnimationProperties; 195 import com.android.systemui.statusbar.notification.stack.NotificationListContainer; 196 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; 197 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; 198 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator; 199 import com.android.systemui.statusbar.notification.stack.StackStateAnimator; 200 import com.android.systemui.statusbar.phone.BounceInterpolator; 201 import com.android.systemui.statusbar.phone.CentralSurfaces; 202 import com.android.systemui.statusbar.phone.DozeParameters; 203 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; 204 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; 205 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; 206 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView; 207 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController; 208 import com.android.systemui.statusbar.phone.KeyguardBypassController; 209 import com.android.systemui.statusbar.phone.KeyguardClockPositionAlgorithm; 210 import com.android.systemui.statusbar.phone.KeyguardStatusBarView; 211 import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController; 212 import com.android.systemui.statusbar.phone.LockscreenGestureLogger; 213 import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; 214 import com.android.systemui.statusbar.phone.ScreenOffAnimationController; 215 import com.android.systemui.statusbar.phone.ScrimController; 216 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 217 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; 218 import com.android.systemui.statusbar.phone.TapAgainViewController; 219 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; 220 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; 221 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; 222 import com.android.systemui.statusbar.policy.ConfigurationController; 223 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; 224 import com.android.systemui.statusbar.policy.KeyguardStateController; 225 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; 226 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; 227 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; 228 import com.android.systemui.statusbar.window.StatusBarWindowStateController; 229 import com.android.systemui.unfold.SysUIUnfoldComponent; 230 import com.android.systemui.util.Compile; 231 import com.android.systemui.util.LargeScreenUtils; 232 import com.android.systemui.util.Utils; 233 import com.android.systemui.util.time.SystemClock; 234 import com.android.wm.shell.animation.FlingAnimationUtils; 235 236 import java.io.PrintWriter; 237 import java.util.ArrayList; 238 import java.util.Collections; 239 import java.util.List; 240 import java.util.Optional; 241 import java.util.function.Consumer; 242 243 import javax.inject.Inject; 244 import javax.inject.Provider; 245 246 import kotlin.Unit; 247 import kotlinx.coroutines.CoroutineDispatcher; 248 249 @CentralSurfacesComponent.CentralSurfacesScope 250 public final class NotificationPanelViewController implements Dumpable { 251 252 public static final String TAG = NotificationPanelView.class.getSimpleName(); 253 public static final float FLING_MAX_LENGTH_SECONDS = 0.6f; 254 public static final float FLING_SPEED_UP_FACTOR = 0.6f; 255 public static final float FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f; 256 public static final float FLING_CLOSING_SPEED_UP_FACTOR = 0.6f; 257 public static final int WAKEUP_ANIMATION_DELAY_MS = 250; 258 private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG); 259 private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE); 260 private static final boolean DEBUG_DRAWABLE = false; 261 private static final VibrationEffect ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT = 262 VibrationEffect.get(VibrationEffect.EFFECT_STRENGTH_MEDIUM, false); 263 /** The parallax amount of the quick settings translation when dragging down the panel. */ 264 public static final float QS_PARALLAX_AMOUNT = 0.175f; 265 /** Fling expanding QS. */ 266 public static final int FLING_EXPAND = 0; 267 /** Fling collapsing QS, potentially stopping when QS becomes QQS. */ 268 public static final int FLING_COLLAPSE = 1; 269 /** Fling until QS is completely hidden. */ 270 public static final int FLING_HIDE = 2; 271 /** The delay to reset the hint text when the hint animation is finished running. */ 272 private static final int HINT_RESET_DELAY_MS = 1200; 273 private static final long ANIMATION_DELAY_ICON_FADE_IN = 274 ActivityLaunchAnimator.TIMINGS.getTotalDuration() 275 - CollapsedStatusBarFragment.FADE_IN_DURATION 276 - CollapsedStatusBarFragment.FADE_IN_DELAY - 48; 277 private static final int NO_FIXED_DURATION = -1; 278 private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L; 279 private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L; 280 281 /** 282 * The factor of the usual high velocity that is needed in order to reach the maximum overshoot 283 * when flinging. A low value will make it that most flings will reach the maximum overshoot. 284 */ 285 private static final float FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT = 0.5f; 286 /** 287 * Maximum time before which we will expand the panel even for slow motions when getting a 288 * touch passed over from launcher. 289 */ 290 private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300; 291 private static final int MAX_DOWN_EVENT_BUFFER_SIZE = 50; 292 private static final String COUNTER_PANEL_OPEN = "panel_open"; 293 public static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs"; 294 private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek"; 295 private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1); 296 private static final Rect EMPTY_RECT = new Rect(); 297 /** 298 * Duration to use for the animator when the keyguard status view alignment changes, and a 299 * custom clock animation is in use. 300 */ 301 private static final int KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION = 1000; 302 303 private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; 304 private final Resources mResources; 305 private final KeyguardStateController mKeyguardStateController; 306 private final SysuiStatusBarStateController mStatusBarStateController; 307 private final AmbientState mAmbientState; 308 private final LockscreenGestureLogger mLockscreenGestureLogger; 309 private final SystemClock mSystemClock; 310 private final ShadeLogger mShadeLog; 311 private final DozeParameters mDozeParameters; 312 private final NotificationStackScrollLayout.OnEmptySpaceClickListener 313 mOnEmptySpaceClickListener = (x, y) -> onEmptySpaceClick(); 314 private final ShadeHeadsUpChangedListener mOnHeadsUpChangedListener = 315 new ShadeHeadsUpChangedListener(); 316 private final ConfigurationListener mConfigurationListener = new ConfigurationListener(); 317 private final SettingsChangeObserver mSettingsChangeObserver; 318 private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener(); 319 private final NotificationPanelView mView; 320 private final VibratorHelper mVibratorHelper; 321 private final MetricsLogger mMetricsLogger; 322 private final ConfigurationController mConfigurationController; 323 private final Provider<FlingAnimationUtils.Builder> mFlingAnimationUtilsBuilder; 324 private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; 325 private final LayoutInflater mLayoutInflater; 326 private final FeatureFlags mFeatureFlags; 327 private final PowerManager mPowerManager; 328 private final AccessibilityManager mAccessibilityManager; 329 private final NotificationWakeUpCoordinator mWakeUpCoordinator; 330 private final PulseExpansionHandler mPulseExpansionHandler; 331 private final KeyguardBypassController mKeyguardBypassController; 332 private final KeyguardUpdateMonitor mUpdateMonitor; 333 private final ConversationNotificationManager mConversationNotificationManager; 334 private final AuthController mAuthController; 335 private final MediaHierarchyManager mMediaHierarchyManager; 336 private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 337 private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; 338 private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; 339 private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; 340 private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; 341 private final FragmentService mFragmentService; 342 private final ScrimController mScrimController; 343 private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; 344 private final TapAgainViewController mTapAgainViewController; 345 private final ShadeHeaderController mShadeHeaderController; 346 private final boolean mVibrateOnOpening; 347 private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); 348 private final FlingAnimationUtils mFlingAnimationUtilsClosing; 349 private final FlingAnimationUtils mFlingAnimationUtilsDismissing; 350 private final LatencyTracker mLatencyTracker; 351 private final DozeLog mDozeLog; 352 /** Whether or not the NotificationPanelView can be expanded or collapsed with a drag. */ 353 private final boolean mNotificationsDragEnabled; 354 private final Interpolator mBounceInterpolator; 355 private final NotificationShadeWindowController mNotificationShadeWindowController; 356 private final ShadeExpansionStateManager mShadeExpansionStateManager; 357 private final FalsingTapListener mFalsingTapListener = this::falsingAdditionalTapRequired; 358 private final AccessibilityDelegate mAccessibilityDelegate = new ShadeAccessibilityDelegate(); 359 private final NotificationGutsManager mGutsManager; 360 private final AlternateBouncerInteractor mAlternateBouncerInteractor; 361 private final QuickSettingsController mQsController; 362 private final InteractionJankMonitor mInteractionJankMonitor; 363 private final TouchHandler mTouchHandler = new TouchHandler(); 364 365 private long mDownTime; 366 private boolean mTouchSlopExceededBeforeDown; 367 private boolean mIsLaunchAnimationRunning; 368 private float mOverExpansion; 369 private CentralSurfaces mCentralSurfaces; 370 private HeadsUpManagerPhone mHeadsUpManager; 371 private float mExpandedHeight = 0; 372 private boolean mTracking; 373 private boolean mHintAnimationRunning; 374 private KeyguardBottomAreaView mKeyguardBottomArea; 375 private boolean mExpanding; 376 private boolean mSplitShadeEnabled; 377 /** The bottom padding reserved for elements of the keyguard measuring notifications. */ 378 private float mKeyguardNotificationBottomPadding; 379 /** 380 * The top padding from where notification should start in lockscreen. 381 * Should be static also during animations and should match the Y of the first notification. 382 */ 383 private float mKeyguardNotificationTopPadding; 384 /** Current max allowed keyguard notifications determined by measuring the panel. */ 385 private int mMaxAllowedKeyguardNotifications; 386 private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; 387 private KeyguardUserSwitcherController mKeyguardUserSwitcherController; 388 private KeyguardStatusBarView mKeyguardStatusBar; 389 private KeyguardStatusBarViewController mKeyguardStatusBarViewController; 390 private KeyguardStatusViewController mKeyguardStatusViewController; 391 private final LockIconViewController mLockIconViewController; 392 private NotificationsQuickSettingsContainer mNotificationContainerParent; 393 private final NotificationsQSContainerController mNotificationsQSContainerController; 394 private final Provider<KeyguardBottomAreaViewController> 395 mKeyguardBottomAreaViewControllerProvider; 396 private boolean mAnimateNextPositionUpdate; 397 private final ScreenOffAnimationController mScreenOffAnimationController; 398 private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; 399 private TrackingStartedListener mTrackingStartedListener; 400 private OpenCloseListener mOpenCloseListener; 401 private GestureRecorder mGestureRecorder; 402 private boolean mPanelExpanded; 403 404 private boolean mKeyguardQsUserSwitchEnabled; 405 private boolean mKeyguardUserSwitcherEnabled; 406 private boolean mDozing; 407 private boolean mDozingOnDown; 408 private boolean mBouncerShowing; 409 private int mBarState; 410 private FlingAnimationUtils mFlingAnimationUtils; 411 private int mStatusBarMinHeight; 412 private int mStatusBarHeaderHeightKeyguard; 413 private float mOverStretchAmount; 414 private float mDownX; 415 private float mDownY; 416 private int mDisplayTopInset = 0; // in pixels 417 private int mDisplayRightInset = 0; // in pixels 418 private int mDisplayLeftInset = 0; // in pixels 419 420 private final KeyguardClockPositionAlgorithm 421 mClockPositionAlgorithm = 422 new KeyguardClockPositionAlgorithm(); 423 private final KeyguardClockPositionAlgorithm.Result 424 mClockPositionResult = 425 new KeyguardClockPositionAlgorithm.Result(); 426 private boolean mIsExpanding; 427 428 private String mHeaderDebugInfo; 429 430 /** 431 * Indicates drag starting height when swiping down or up on heads-up notifications. 432 * This usually serves as a threshold from when shade expansion should really start. Otherwise 433 * this value would be height of shade and it will be immediately expanded to some extent. 434 */ 435 private int mHeadsUpStartHeight; 436 private HeadsUpTouchHelper mHeadsUpTouchHelper; 437 private boolean mListenForHeadsUp; 438 private int mNavigationBarBottomHeight; 439 private boolean mExpandingFromHeadsUp; 440 private boolean mCollapsedOnDown; 441 private boolean mClosingWithAlphaFadeOut; 442 private boolean mHeadsUpAnimatingAway; 443 private final FalsingManager mFalsingManager; 444 private final FalsingCollector mFalsingCollector; 445 446 private boolean mShowIconsWhenExpanded; 447 private int mIndicationBottomPadding; 448 private int mAmbientIndicationBottomPadding; 449 /** Whether the notifications are displayed full width (no margins on the side). */ 450 private boolean mIsFullWidth; 451 private boolean mBlockingExpansionForCurrentTouch; 452 // Following variables maintain state of events when input focus transfer may occur. 453 private boolean mExpectingSynthesizedDown; 454 private boolean mLastEventSynthesizedDown; 455 456 /** Current dark amount that follows regular interpolation curve of animation. */ 457 private float mInterpolatedDarkAmount; 458 /** 459 * Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the 460 * interpolation curve is different. 461 */ 462 private float mLinearDarkAmount; 463 private boolean mPulsing; 464 private boolean mHideIconsDuringLaunchAnimation = true; 465 private int mStackScrollerMeasuringPass; 466 /** Non-null if a heads-up notification's position is being tracked. */ 467 @Nullable 468 private ExpandableNotificationRow mTrackedHeadsUpNotification; 469 private final ArrayList<Consumer<ExpandableNotificationRow>> 470 mTrackingHeadsUpListeners = new ArrayList<>(); 471 private HeadsUpAppearanceController mHeadsUpAppearanceController; 472 473 private int mPanelAlpha; 474 private Runnable mPanelAlphaEndAction; 475 private float mBottomAreaShadeAlpha; 476 final ValueAnimator mBottomAreaShadeAlphaAnimator; 477 private final AnimatableProperty mPanelAlphaAnimator = AnimatableProperty.from("panelAlpha", 478 NotificationPanelView::setPanelAlphaInternal, 479 NotificationPanelView::getCurrentPanelAlpha, 480 R.id.panel_alpha_animator_tag, R.id.panel_alpha_animator_start_tag, 481 R.id.panel_alpha_animator_end_tag); 482 private final AnimationProperties mPanelAlphaOutPropertiesAnimator = 483 new AnimationProperties().setDuration(150).setCustomInterpolator( 484 mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_OUT); 485 private final AnimationProperties mPanelAlphaInPropertiesAnimator = 486 new AnimationProperties().setDuration(200).setAnimationEndAction((property) -> { 487 if (mPanelAlphaEndAction != null) { 488 mPanelAlphaEndAction.run(); 489 } 490 }).setCustomInterpolator( 491 mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN); 492 493 private final CommandQueue mCommandQueue; 494 private final UserManager mUserManager; 495 private final MediaDataManager mMediaDataManager; 496 @PanelState 497 private int mCurrentPanelState = STATE_CLOSED; 498 private final SysUiState mSysUiState; 499 private final NotificationShadeDepthController mDepthController; 500 private final NavigationBarController mNavigationBarController; 501 private final int mDisplayId; 502 503 private final KeyguardIndicationController mKeyguardIndicationController; 504 private int mHeadsUpInset; 505 private boolean mHeadsUpPinnedMode; 506 private boolean mAllowExpandForSmallExpansion; 507 private Runnable mExpandAfterLayoutRunnable; 508 private Runnable mHideExpandedRunnable; 509 510 /** The maximum overshoot allowed for the top padding for the full shade transition. */ 511 private int mMaxOverscrollAmountForPulse; 512 513 /** Whether a collapse that started on the panel should allow the panel to intercept. */ 514 private boolean mIsPanelCollapseOnQQS; 515 516 /** Alpha of the views which only show on the keyguard but not in shade / shade locked. */ 517 private float mKeyguardOnlyContentAlpha = 1.0f; 518 /** Y translation of the views that only show on the keyguard but in shade / shade locked. */ 519 private int mKeyguardOnlyTransitionTranslationY = 0; 520 private float mUdfpsMaxYBurnInOffset; 521 /** Are we currently in gesture navigation. */ 522 private boolean mIsGestureNavigation; 523 private int mOldLayoutDirection; 524 private NotificationShelfController mNotificationShelfController; 525 526 private final ContentResolver mContentResolver; 527 private float mMinFraction; 528 529 private final KeyguardMediaController mKeyguardMediaController; 530 531 private boolean mStatusViewCentered = true; 532 533 private final Optional<KeyguardUnfoldTransition> mKeyguardUnfoldTransition; 534 private final Optional<NotificationPanelUnfoldAnimationController> 535 mNotificationPanelUnfoldAnimationController; 536 537 /** The drag distance required to fully expand the split shade. */ 538 private int mSplitShadeFullTransitionDistance; 539 /** The drag distance required to fully transition scrims. */ 540 private int mSplitShadeScrimTransitionDistance; 541 542 private final NotificationListContainer mNotificationListContainer; 543 private final NotificationStackSizeCalculator mNotificationStackSizeCalculator; 544 private final NPVCDownEventState.Buffer mLastDownEvents; 545 private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel; 546 private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; 547 private float mMinExpandHeight; 548 private final ShadeHeightLogger mShadeHeightLogger; 549 private boolean mPanelUpdateWhenAnimatorEnds; 550 private boolean mHasVibratedOnOpen = false; 551 private int mFixedDuration = NO_FIXED_DURATION; 552 /** The overshoot amount when the panel flings open. */ 553 private float mPanelFlingOvershootAmount; 554 /** The amount of pixels that we have overexpanded the last time with a gesture. */ 555 private float mLastGesturedOverExpansion = -1; 556 /** Whether the current animator is the spring back animation. */ 557 private boolean mIsSpringBackAnimation; 558 private float mHintDistance; 559 private float mInitialOffsetOnTouch; 560 private boolean mCollapsedAndHeadsUpOnDown; 561 private float mExpandedFraction = 0; 562 private float mExpansionDragDownAmountPx = 0; 563 private boolean mPanelClosedOnDown; 564 private boolean mHasLayoutedSinceDown; 565 private float mUpdateFlingVelocity; 566 private boolean mUpdateFlingOnLayout; 567 private boolean mClosing; 568 private boolean mTouchSlopExceeded; 569 private int mTrackingPointer; 570 private int mTouchSlop; 571 private float mSlopMultiplier; 572 private boolean mTouchAboveFalsingThreshold; 573 private boolean mTouchStartedInEmptyArea; 574 private boolean mMotionAborted; 575 private boolean mUpwardsWhenThresholdReached; 576 private boolean mAnimatingOnDown; 577 private boolean mHandlingPointerUp; 578 private ValueAnimator mHeightAnimator; 579 /** Whether an instant expand request is currently pending and we are waiting for layout. */ 580 private boolean mInstantExpanding; 581 private boolean mAnimateAfterExpanding; 582 private boolean mIsFlinging; 583 private String mViewName; 584 private float mInitialExpandY; 585 private float mInitialExpandX; 586 private boolean mTouchDisabled; 587 private boolean mInitialTouchFromKeyguard; 588 /** Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time. */ 589 private float mNextCollapseSpeedUpFactor = 1.0f; 590 private boolean mGestureWaitForTouchSlop; 591 private boolean mIgnoreXTouchSlop; 592 private boolean mExpandLatencyTracking; 593 /** 594 * Whether we're waking up and will play the delayed doze animation in 595 * {@link NotificationWakeUpCoordinator}. If so, we'll want to keep the clock centered until the 596 * delayed doze animation starts. 597 */ 598 private boolean mWillPlayDelayedDozeAmountAnimation = false; 599 private final DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel; 600 private final OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel; 601 private final LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel; 602 private final GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel; 603 private final LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel; 604 605 private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; 606 private final KeyguardInteractor mKeyguardInteractor; 607 private final CoroutineDispatcher mMainDispatcher; 608 private boolean mIsOcclusionTransitionRunning = false; 609 private int mDreamingToLockscreenTransitionTranslationY; 610 private int mOccludedToLockscreenTransitionTranslationY; 611 private int mLockscreenToDreamingTransitionTranslationY; 612 private int mGoneToDreamingTransitionTranslationY; 613 private int mLockscreenToOccludedTransitionTranslationY; 614 615 private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */, 616 mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */); 617 private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable = 618 () -> mKeyguardBottomArea.setVisibility(View.GONE); 619 private final Runnable mHeadsUpExistenceChangedRunnable = () -> { 620 setHeadsUpAnimatingAway(false); 621 updatePanelExpansionAndVisibility(); 622 }; 623 private final Runnable mMaybeHideExpandedRunnable = () -> { 624 if (getExpandedFraction() == 0.0f) { 625 postToView(mHideExpandedRunnable); 626 } 627 }; 628 629 private final Consumer<TransitionStep> mDreamingToLockscreenTransition = 630 (TransitionStep step) -> { 631 mIsOcclusionTransitionRunning = 632 step.getTransitionState() == TransitionState.RUNNING; 633 }; 634 635 private final Consumer<TransitionStep> mOccludedToLockscreenTransition = 636 (TransitionStep step) -> { 637 mIsOcclusionTransitionRunning = 638 step.getTransitionState() == TransitionState.RUNNING; 639 }; 640 641 private final Consumer<TransitionStep> mLockscreenToDreamingTransition = 642 (TransitionStep step) -> { 643 mIsOcclusionTransitionRunning = 644 step.getTransitionState() == TransitionState.RUNNING; 645 }; 646 647 private final Consumer<TransitionStep> mGoneToDreamingTransition = 648 (TransitionStep step) -> { 649 mIsOcclusionTransitionRunning = 650 step.getTransitionState() == TransitionState.RUNNING; 651 }; 652 653 private final Consumer<TransitionStep> mLockscreenToOccludedTransition = 654 (TransitionStep step) -> { 655 mIsOcclusionTransitionRunning = 656 step.getTransitionState() == TransitionState.RUNNING; 657 }; 658 659 private final TransitionListenerAdapter mKeyguardStatusAlignmentTransitionListener = 660 new TransitionListenerAdapter() { 661 @Override 662 public void onTransitionCancel(Transition transition) { 663 mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); 664 } 665 666 @Override 667 public void onTransitionEnd(Transition transition) { 668 mInteractionJankMonitor.end(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); 669 } 670 }; 671 672 @Inject NotificationPanelViewController(NotificationPanelView view, @Main Handler handler, LayoutInflater layoutInflater, FeatureFlags featureFlags, NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler, DynamicPrivacyController dynamicPrivacyController, KeyguardBypassController bypassController, FalsingManager falsingManager, FalsingCollector falsingCollector, KeyguardStateController keyguardStateController, StatusBarStateController statusBarStateController, StatusBarWindowStateController statusBarWindowStateController, NotificationShadeWindowController notificationShadeWindowController, DozeLog dozeLog, DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper, LatencyTracker latencyTracker, PowerManager powerManager, AccessibilityManager accessibilityManager, @DisplayId int displayId, KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger, ShadeLogger shadeLogger, ShadeHeightLogger shadeHeightLogger, ConfigurationController configurationController, Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder, StatusBarTouchableRegionManager statusBarTouchableRegionManager, ConversationNotificationManager conversationNotificationManager, MediaHierarchyManager mediaHierarchyManager, StatusBarKeyguardViewManager statusBarKeyguardViewManager, NotificationGutsManager gutsManager, NotificationsQSContainerController notificationsQSContainerController, NotificationStackScrollLayoutController notificationStackScrollLayoutController, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory, KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory, LockscreenShadeTransitionController lockscreenShadeTransitionController, AuthController authController, ScrimController scrimController, UserManager userManager, MediaDataManager mediaDataManager, NotificationShadeDepthController notificationShadeDepthController, AmbientState ambientState, LockIconViewController lockIconViewController, KeyguardMediaController keyguardMediaController, TapAgainViewController tapAgainViewController, NavigationModeController navigationModeController, NavigationBarController navigationBarController, QuickSettingsController quickSettingsController, FragmentService fragmentService, ContentResolver contentResolver, ShadeHeaderController shadeHeaderController, ScreenOffAnimationController screenOffAnimationController, LockscreenGestureLogger lockscreenGestureLogger, ShadeExpansionStateManager shadeExpansionStateManager, Optional<SysUIUnfoldComponent> unfoldComponent, SysUiState sysUiState, Provider<KeyguardBottomAreaViewController> keyguardBottomAreaViewControllerProvider, KeyguardUnlockAnimationController keyguardUnlockAnimationController, KeyguardIndicationController keyguardIndicationController, NotificationListContainer notificationListContainer, NotificationStackSizeCalculator notificationStackSizeCalculator, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, ShadeTransitionController shadeTransitionController, InteractionJankMonitor interactionJankMonitor, SystemClock systemClock, KeyguardBottomAreaViewModel keyguardBottomAreaViewModel, KeyguardBottomAreaInteractor keyguardBottomAreaInteractor, AlternateBouncerInteractor alternateBouncerInteractor, DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel, OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel, LockscreenToDreamingTransitionViewModel lockscreenToDreamingTransitionViewModel, GoneToDreamingTransitionViewModel goneToDreamingTransitionViewModel, LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel, @Main CoroutineDispatcher mainDispatcher, KeyguardTransitionInteractor keyguardTransitionInteractor, DumpManager dumpManager, KeyguardLongPressViewModel keyguardLongPressViewModel, KeyguardInteractor keyguardInteractor)673 public NotificationPanelViewController(NotificationPanelView view, 674 @Main Handler handler, 675 LayoutInflater layoutInflater, 676 FeatureFlags featureFlags, 677 NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler, 678 DynamicPrivacyController dynamicPrivacyController, 679 KeyguardBypassController bypassController, FalsingManager falsingManager, 680 FalsingCollector falsingCollector, 681 KeyguardStateController keyguardStateController, 682 StatusBarStateController statusBarStateController, 683 StatusBarWindowStateController statusBarWindowStateController, 684 NotificationShadeWindowController notificationShadeWindowController, 685 DozeLog dozeLog, 686 DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper, 687 LatencyTracker latencyTracker, PowerManager powerManager, 688 AccessibilityManager accessibilityManager, @DisplayId int displayId, 689 KeyguardUpdateMonitor keyguardUpdateMonitor, 690 MetricsLogger metricsLogger, 691 ShadeLogger shadeLogger, 692 ShadeHeightLogger shadeHeightLogger, 693 ConfigurationController configurationController, 694 Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder, 695 StatusBarTouchableRegionManager statusBarTouchableRegionManager, 696 ConversationNotificationManager conversationNotificationManager, 697 MediaHierarchyManager mediaHierarchyManager, 698 StatusBarKeyguardViewManager statusBarKeyguardViewManager, 699 NotificationGutsManager gutsManager, 700 NotificationsQSContainerController notificationsQSContainerController, 701 NotificationStackScrollLayoutController notificationStackScrollLayoutController, 702 KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, 703 KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory, 704 KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, 705 KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory, 706 LockscreenShadeTransitionController lockscreenShadeTransitionController, 707 AuthController authController, 708 ScrimController scrimController, 709 UserManager userManager, 710 MediaDataManager mediaDataManager, 711 NotificationShadeDepthController notificationShadeDepthController, 712 AmbientState ambientState, 713 LockIconViewController lockIconViewController, 714 KeyguardMediaController keyguardMediaController, 715 TapAgainViewController tapAgainViewController, 716 NavigationModeController navigationModeController, 717 NavigationBarController navigationBarController, 718 QuickSettingsController quickSettingsController, 719 FragmentService fragmentService, 720 ContentResolver contentResolver, 721 ShadeHeaderController shadeHeaderController, 722 ScreenOffAnimationController screenOffAnimationController, 723 LockscreenGestureLogger lockscreenGestureLogger, 724 ShadeExpansionStateManager shadeExpansionStateManager, 725 Optional<SysUIUnfoldComponent> unfoldComponent, 726 SysUiState sysUiState, 727 Provider<KeyguardBottomAreaViewController> keyguardBottomAreaViewControllerProvider, 728 KeyguardUnlockAnimationController keyguardUnlockAnimationController, 729 KeyguardIndicationController keyguardIndicationController, 730 NotificationListContainer notificationListContainer, 731 NotificationStackSizeCalculator notificationStackSizeCalculator, 732 UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, 733 ShadeTransitionController shadeTransitionController, 734 InteractionJankMonitor interactionJankMonitor, 735 SystemClock systemClock, 736 KeyguardBottomAreaViewModel keyguardBottomAreaViewModel, 737 KeyguardBottomAreaInteractor keyguardBottomAreaInteractor, 738 AlternateBouncerInteractor alternateBouncerInteractor, 739 DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel, 740 OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel, 741 LockscreenToDreamingTransitionViewModel lockscreenToDreamingTransitionViewModel, 742 GoneToDreamingTransitionViewModel goneToDreamingTransitionViewModel, 743 LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel, 744 @Main CoroutineDispatcher mainDispatcher, 745 KeyguardTransitionInteractor keyguardTransitionInteractor, 746 DumpManager dumpManager, 747 KeyguardLongPressViewModel keyguardLongPressViewModel, 748 KeyguardInteractor keyguardInteractor) { 749 mInteractionJankMonitor = interactionJankMonitor; 750 keyguardStateController.addCallback(new KeyguardStateController.Callback() { 751 @Override 752 public void onKeyguardFadingAwayChanged() { 753 updateExpandedHeightToMaxHeight(); 754 } 755 }); 756 mAmbientState = ambientState; 757 mView = view; 758 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; 759 mLockscreenGestureLogger = lockscreenGestureLogger; 760 mShadeExpansionStateManager = shadeExpansionStateManager; 761 mShadeLog = shadeLogger; 762 mShadeHeightLogger = shadeHeightLogger; 763 mGutsManager = gutsManager; 764 mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel; 765 mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel; 766 mLockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel; 767 mGoneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel; 768 mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel; 769 mKeyguardTransitionInteractor = keyguardTransitionInteractor; 770 mKeyguardInteractor = keyguardInteractor; 771 mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { 772 @Override 773 public void onViewAttachedToWindow(View v) { 774 mViewName = mResources.getResourceName(mView.getId()); 775 } 776 777 @Override 778 public void onViewDetachedFromWindow(View v) {} 779 }); 780 781 mView.addOnLayoutChangeListener(new ShadeLayoutChangeListener()); 782 mView.setOnTouchListener(getTouchHandler()); 783 mView.setOnConfigurationChangedListener(config -> loadDimens()); 784 785 mResources = mView.getResources(); 786 mKeyguardStateController = keyguardStateController; 787 mQsController = quickSettingsController; 788 mKeyguardIndicationController = keyguardIndicationController; 789 mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController; 790 mNotificationShadeWindowController = notificationShadeWindowController; 791 FlingAnimationUtils.Builder fauBuilder = flingAnimationUtilsBuilder.get(); 792 mFlingAnimationUtils = fauBuilder 793 .reset() 794 .setMaxLengthSeconds(FLING_MAX_LENGTH_SECONDS) 795 .setSpeedUpFactor(FLING_SPEED_UP_FACTOR) 796 .build(); 797 mFlingAnimationUtilsClosing = fauBuilder 798 .reset() 799 .setMaxLengthSeconds(FLING_CLOSING_MAX_LENGTH_SECONDS) 800 .setSpeedUpFactor(FLING_CLOSING_SPEED_UP_FACTOR) 801 .build(); 802 mFlingAnimationUtilsDismissing = fauBuilder 803 .reset() 804 .setMaxLengthSeconds(0.5f) 805 .setSpeedUpFactor(0.6f) 806 .setX2(0.6f) 807 .setY2(0.84f) 808 .build(); 809 mLatencyTracker = latencyTracker; 810 mBounceInterpolator = new BounceInterpolator(); 811 mFalsingManager = falsingManager; 812 mDozeLog = dozeLog; 813 mNotificationsDragEnabled = mResources.getBoolean( 814 R.bool.config_enableNotificationShadeDrag); 815 mVibratorHelper = vibratorHelper; 816 mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation); 817 mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; 818 mSystemClock = systemClock; 819 mKeyguardMediaController = keyguardMediaController; 820 mMetricsLogger = metricsLogger; 821 mConfigurationController = configurationController; 822 mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder; 823 mMediaHierarchyManager = mediaHierarchyManager; 824 mNotificationsQSContainerController = notificationsQSContainerController; 825 mNotificationListContainer = notificationListContainer; 826 mNotificationStackSizeCalculator = notificationStackSizeCalculator; 827 mNavigationBarController = navigationBarController; 828 mKeyguardBottomAreaViewControllerProvider = keyguardBottomAreaViewControllerProvider; 829 mNotificationsQSContainerController.init(); 830 mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; 831 mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; 832 mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory; 833 mDepthController = notificationShadeDepthController; 834 mContentResolver = contentResolver; 835 mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory; 836 mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; 837 mFragmentService = fragmentService; 838 mSettingsChangeObserver = new SettingsChangeObserver(handler); 839 mSplitShadeEnabled = 840 LargeScreenUtils.shouldUseSplitNotificationShade(mResources); 841 mView.setWillNotDraw(!DEBUG_DRAWABLE); 842 mShadeHeaderController = shadeHeaderController; 843 mLayoutInflater = layoutInflater; 844 mFeatureFlags = featureFlags; 845 mFalsingCollector = falsingCollector; 846 mPowerManager = powerManager; 847 mWakeUpCoordinator = coordinator; 848 mMainDispatcher = mainDispatcher; 849 mAccessibilityManager = accessibilityManager; 850 mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); 851 setPanelAlpha(255, false /* animate */); 852 mCommandQueue = commandQueue; 853 mDisplayId = displayId; 854 mPulseExpansionHandler = pulseExpansionHandler; 855 mDozeParameters = dozeParameters; 856 mScrimController = scrimController; 857 mUserManager = userManager; 858 mMediaDataManager = mediaDataManager; 859 mTapAgainViewController = tapAgainViewController; 860 mSysUiState = sysUiState; 861 statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged); 862 mKeyguardBypassController = bypassController; 863 mUpdateMonitor = keyguardUpdateMonitor; 864 mLockscreenShadeTransitionController = lockscreenShadeTransitionController; 865 lockscreenShadeTransitionController.setNotificationPanelController(this); 866 shadeTransitionController.setNotificationPanelViewController(this); 867 dynamicPrivacyController.addListener(this::onDynamicPrivacyChanged); 868 quickSettingsController.setExpansionHeightListener(this::onQsSetExpansionHeightCalled); 869 quickSettingsController.setQsStateUpdateListener(this::onQsStateUpdated); 870 quickSettingsController.setApplyClippingImmediatelyListener( 871 this::onQsClippingImmediatelyApplied); 872 quickSettingsController.setFlingQsWithoutClickListener(this::onFlingQsWithoutClick); 873 quickSettingsController.setExpansionHeightSetToMaxListener(this::onExpansionHeightSetToMax); 874 shadeExpansionStateManager.addStateListener(this::onPanelStateChanged); 875 876 mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0); 877 mBottomAreaShadeAlphaAnimator.addUpdateListener(animation -> { 878 mBottomAreaShadeAlpha = (float) animation.getAnimatedValue(); 879 updateKeyguardBottomAreaAlpha(); 880 }); 881 mBottomAreaShadeAlphaAnimator.setDuration(160); 882 mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT); 883 mConversationNotificationManager = conversationNotificationManager; 884 mAuthController = authController; 885 mLockIconViewController = lockIconViewController; 886 mScreenOffAnimationController = screenOffAnimationController; 887 mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; 888 mLastDownEvents = new NPVCDownEventState.Buffer(MAX_DOWN_EVENT_BUFFER_SIZE); 889 890 int currentMode = navigationModeController.addListener( 891 mode -> mIsGestureNavigation = QuickStepContract.isGesturalMode(mode)); 892 mIsGestureNavigation = QuickStepContract.isGesturalMode(currentMode); 893 894 mView.setBackgroundColor(Color.TRANSPARENT); 895 ShadeAttachStateChangeListener 896 onAttachStateChangeListener = new ShadeAttachStateChangeListener(); 897 mView.addOnAttachStateChangeListener(onAttachStateChangeListener); 898 if (mView.isAttachedToWindow()) { 899 onAttachStateChangeListener.onViewAttachedToWindow(mView); 900 } 901 902 mView.setOnApplyWindowInsetsListener((v, insets) -> onApplyShadeWindowInsets(insets)); 903 904 if (DEBUG_DRAWABLE) { 905 mView.getOverlay().add(new DebugDrawable(this, mView, 906 mNotificationStackScrollLayoutController, mLockIconViewController, 907 mQsController)); 908 } 909 910 mKeyguardUnfoldTransition = unfoldComponent.map( 911 SysUIUnfoldComponent::getKeyguardUnfoldTransition); 912 mNotificationPanelUnfoldAnimationController = unfoldComponent.map( 913 SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController); 914 915 updateUserSwitcherFlags(); 916 mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel; 917 mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor; 918 KeyguardLongPressViewBinder.bind( 919 mView.requireViewById(R.id.keyguard_long_press), 920 keyguardLongPressViewModel, 921 () -> { 922 onEmptySpaceClick(); 923 return Unit.INSTANCE; 924 }, 925 mFalsingManager); 926 onFinishInflate(); 927 keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener( 928 new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() { 929 @Override 930 public void onUnlockAnimationFinished() { 931 unlockAnimationFinished(); 932 } 933 934 @Override 935 public void onUnlockAnimationStarted( 936 boolean playingCannedAnimation, 937 boolean isWakeAndUnlock, 938 long startDelay, 939 long unlockAnimationDuration) { 940 unlockAnimationStarted(playingCannedAnimation, isWakeAndUnlock, startDelay); 941 } 942 }); 943 mAlternateBouncerInteractor = alternateBouncerInteractor; 944 dumpManager.registerDumpable(this); 945 } 946 unlockAnimationFinished()947 private void unlockAnimationFinished() { 948 // Make sure the clock is in the correct position after the unlock animation 949 // so that it's not in the wrong place when we show the keyguard again. 950 positionClockAndNotifications(true /* forceClockUpdate */); 951 } 952 unlockAnimationStarted( boolean playingCannedAnimation, boolean isWakeAndUnlock, long unlockAnimationStartDelay)953 private void unlockAnimationStarted( 954 boolean playingCannedAnimation, 955 boolean isWakeAndUnlock, 956 long unlockAnimationStartDelay) { 957 // Disable blurs while we're unlocking so that panel expansion does not 958 // cause blurring. This will eventually be re-enabled by the panel view on 959 // ACTION_UP, since the user's finger might still be down after a swipe to 960 // unlock gesture, and we don't want that to cause blurring either. 961 mDepthController.setBlursDisabledForUnlock(mTracking); 962 963 if (playingCannedAnimation && !isWakeAndUnlock) { 964 // Hide the panel so it's not in the way or the surface behind the 965 // keyguard, which will be appearing. If we're wake and unlocking, the 966 // lock screen is hidden instantly so should not be flung away. 967 if (isTracking() || mIsFlinging) { 968 // Instant collapse the notification panel since the notification 969 // panel is already in the middle animating 970 onTrackingStopped(false); 971 instantCollapse(); 972 } else { 973 mView.animate().cancel(); 974 mView.animate() 975 .alpha(0f) 976 .setStartDelay(0) 977 // Translate up by 4%. 978 .translationY(mView.getHeight() * -0.04f) 979 // This start delay is to give us time to animate out before 980 // the launcher icons animation starts, so use that as our 981 // duration. 982 .setDuration(unlockAnimationStartDelay) 983 .setInterpolator(EMPHASIZED_ACCELERATE) 984 .withEndAction(() -> { 985 instantCollapse(); 986 mView.setAlpha(1f); 987 mView.setTranslationY(0f); 988 }) 989 .start(); 990 } 991 } 992 } 993 994 @VisibleForTesting onFinishInflate()995 void onFinishInflate() { 996 loadDimens(); 997 mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header); 998 999 FrameLayout userAvatarContainer = null; 1000 KeyguardUserSwitcherView keyguardUserSwitcherView = null; 1001 1002 if (mKeyguardUserSwitcherEnabled && mUserManager.isUserSwitcherEnabled( 1003 mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user))) { 1004 if (mKeyguardQsUserSwitchEnabled) { 1005 ViewStub stub = mView.findViewById(R.id.keyguard_qs_user_switch_stub); 1006 userAvatarContainer = (FrameLayout) stub.inflate(); 1007 } else { 1008 ViewStub stub = mView.findViewById(R.id.keyguard_user_switcher_stub); 1009 keyguardUserSwitcherView = (KeyguardUserSwitcherView) stub.inflate(); 1010 } 1011 } 1012 1013 mKeyguardStatusBarViewController = 1014 mKeyguardStatusBarViewComponentFactory.build( 1015 mKeyguardStatusBar, 1016 mNotificationPanelViewStateProvider) 1017 .getKeyguardStatusBarViewController(); 1018 mKeyguardStatusBarViewController.init(); 1019 1020 mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); 1021 updateViewControllers( 1022 mView.findViewById(R.id.keyguard_status_view), 1023 userAvatarContainer, 1024 keyguardUserSwitcherView); 1025 1026 NotificationStackScrollLayout stackScrollLayout = mView.findViewById( 1027 R.id.notification_stack_scroller); 1028 mNotificationStackScrollLayoutController.attach(stackScrollLayout); 1029 mNotificationStackScrollLayoutController.setOnHeightChangedListener( 1030 new NsslHeightChangedListener()); 1031 mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener( 1032 mOnEmptySpaceClickListener); 1033 mQsController.initNotificationStackScrollLayoutController(); 1034 mShadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged); 1035 addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp); 1036 setKeyguardBottomArea(mView.findViewById(R.id.keyguard_bottom_area)); 1037 1038 initBottomArea(); 1039 1040 mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController); 1041 mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController); 1042 mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() { 1043 @Override 1044 public void onFullyHiddenChanged(boolean isFullyHidden) { 1045 mKeyguardStatusBarViewController.updateForHeadsUp(); 1046 } 1047 1048 @Override 1049 public void onPulseExpansionChanged(boolean expandingChanged) { 1050 if (mKeyguardBypassController.getBypassEnabled()) { 1051 // Position the notifications while dragging down while pulsing 1052 requestScrollerTopPaddingUpdate(false /* animate */); 1053 } 1054 } 1055 1056 @Override 1057 public void onDelayedDozeAmountAnimationRunning(boolean running) { 1058 // On running OR finished, the animation is no longer waiting to play 1059 setWillPlayDelayedDozeAmountAnimation(false); 1060 } 1061 }); 1062 1063 mView.setRtlChangeListener(layoutDirection -> { 1064 if (layoutDirection != mOldLayoutDirection) { 1065 mOldLayoutDirection = layoutDirection; 1066 } 1067 }); 1068 1069 mView.setAccessibilityDelegate(mAccessibilityDelegate); 1070 if (mSplitShadeEnabled) { 1071 updateResources(); 1072 } 1073 1074 mTapAgainViewController.init(); 1075 mShadeHeaderController.init(); 1076 mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView)); 1077 mNotificationPanelUnfoldAnimationController.ifPresent(controller -> 1078 controller.setup(mNotificationContainerParent)); 1079 1080 // Dreaming->Lockscreen 1081 collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(), 1082 mDreamingToLockscreenTransition, mMainDispatcher); 1083 collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(), 1084 setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); 1085 collectFlow(mView, mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY( 1086 mDreamingToLockscreenTransitionTranslationY), 1087 setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); 1088 1089 // Occluded->Lockscreen 1090 collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(), 1091 mOccludedToLockscreenTransition, mMainDispatcher); 1092 collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(), 1093 setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); 1094 collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY( 1095 mOccludedToLockscreenTransitionTranslationY), 1096 setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); 1097 1098 // Lockscreen->Dreaming 1099 collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(), 1100 mLockscreenToDreamingTransition, mMainDispatcher); 1101 collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(), 1102 setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); 1103 collectFlow(mView, mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY( 1104 mLockscreenToDreamingTransitionTranslationY), 1105 setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); 1106 1107 // Gone->Dreaming 1108 collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(), 1109 mGoneToDreamingTransition, mMainDispatcher); 1110 collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(), 1111 setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); 1112 collectFlow(mView, mGoneToDreamingTransitionViewModel.lockscreenTranslationY( 1113 mGoneToDreamingTransitionTranslationY), 1114 setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); 1115 1116 // Lockscreen->Occluded 1117 collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(), 1118 mLockscreenToOccludedTransition, mMainDispatcher); 1119 collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(), 1120 setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); 1121 collectFlow(mView, mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY( 1122 mLockscreenToOccludedTransitionTranslationY), 1123 setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); 1124 } 1125 1126 @VisibleForTesting loadDimens()1127 void loadDimens() { 1128 final ViewConfiguration configuration = ViewConfiguration.get(this.mView.getContext()); 1129 mTouchSlop = configuration.getScaledTouchSlop(); 1130 mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 1131 mHintDistance = mResources.getDimension(R.dimen.hint_move_distance); 1132 mPanelFlingOvershootAmount = mResources.getDimension(R.dimen.panel_overshoot_amount); 1133 mFlingAnimationUtils = mFlingAnimationUtilsBuilder.get() 1134 .setMaxLengthSeconds(0.4f).build(); 1135 mStatusBarMinHeight = SystemBarUtils.getStatusBarHeight(mView.getContext()); 1136 mStatusBarHeaderHeightKeyguard = Utils.getStatusBarHeaderHeightKeyguard(mView.getContext()); 1137 mClockPositionAlgorithm.loadDimens(mResources); 1138 mIndicationBottomPadding = mResources.getDimensionPixelSize( 1139 R.dimen.keyguard_indication_bottom_padding); 1140 int statusbarHeight = SystemBarUtils.getStatusBarHeight(mView.getContext()); 1141 mHeadsUpInset = statusbarHeight + mResources.getDimensionPixelSize( 1142 R.dimen.heads_up_status_bar_padding); 1143 mMaxOverscrollAmountForPulse = mResources.getDimensionPixelSize( 1144 R.dimen.pulse_expansion_max_top_overshoot); 1145 mUdfpsMaxYBurnInOffset = mResources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y); 1146 mSplitShadeScrimTransitionDistance = mResources.getDimensionPixelSize( 1147 R.dimen.split_shade_scrim_transition_distance); 1148 mDreamingToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize( 1149 R.dimen.dreaming_to_lockscreen_transition_lockscreen_translation_y); 1150 mOccludedToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize( 1151 R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y); 1152 mLockscreenToDreamingTransitionTranslationY = mResources.getDimensionPixelSize( 1153 R.dimen.lockscreen_to_dreaming_transition_lockscreen_translation_y); 1154 mGoneToDreamingTransitionTranslationY = mResources.getDimensionPixelSize( 1155 R.dimen.gone_to_dreaming_transition_lockscreen_translation_y); 1156 mLockscreenToOccludedTransitionTranslationY = mResources.getDimensionPixelSize( 1157 R.dimen.lockscreen_to_occluded_transition_lockscreen_translation_y); 1158 // TODO (b/265193930): remove this and make QsController listen to NotificationPanelViews 1159 mQsController.loadDimens(); 1160 } 1161 updateViewControllers(KeyguardStatusView keyguardStatusView, FrameLayout userAvatarView, KeyguardUserSwitcherView keyguardUserSwitcherView)1162 private void updateViewControllers(KeyguardStatusView keyguardStatusView, 1163 FrameLayout userAvatarView, 1164 KeyguardUserSwitcherView keyguardUserSwitcherView) { 1165 // Re-associate the KeyguardStatusViewController 1166 KeyguardStatusViewComponent statusViewComponent = 1167 mKeyguardStatusViewComponentFactory.build(keyguardStatusView); 1168 mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController(); 1169 mKeyguardStatusViewController.init(); 1170 updateClockAppearance(); 1171 1172 if (mKeyguardUserSwitcherController != null) { 1173 // Try to close the switcher so that callbacks are triggered if necessary. 1174 // Otherwise, NPV can get into a state where some of the views are still hidden 1175 mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(false); 1176 } 1177 1178 mKeyguardQsUserSwitchController = null; 1179 mKeyguardUserSwitcherController = null; 1180 1181 // Re-associate the KeyguardUserSwitcherController 1182 if (userAvatarView != null) { 1183 KeyguardQsUserSwitchComponent userSwitcherComponent = 1184 mKeyguardQsUserSwitchComponentFactory.build(userAvatarView); 1185 mKeyguardQsUserSwitchController = 1186 userSwitcherComponent.getKeyguardQsUserSwitchController(); 1187 mKeyguardQsUserSwitchController.init(); 1188 mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(true); 1189 } else if (keyguardUserSwitcherView != null) { 1190 KeyguardUserSwitcherComponent userSwitcherComponent = 1191 mKeyguardUserSwitcherComponentFactory.build(keyguardUserSwitcherView); 1192 mKeyguardUserSwitcherController = 1193 userSwitcherComponent.getKeyguardUserSwitcherController(); 1194 mKeyguardUserSwitcherController.init(); 1195 mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(true); 1196 } else { 1197 mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(false); 1198 } 1199 } 1200 updateResources()1201 public void updateResources() { 1202 final boolean newSplitShadeEnabled = 1203 LargeScreenUtils.shouldUseSplitNotificationShade(mResources); 1204 final boolean splitShadeChanged = mSplitShadeEnabled != newSplitShadeEnabled; 1205 mSplitShadeEnabled = newSplitShadeEnabled; 1206 mQsController.updateResources(); 1207 mNotificationsQSContainerController.updateResources(); 1208 updateKeyguardStatusViewAlignment(/* animate= */false); 1209 mKeyguardMediaController.refreshMediaPosition(); 1210 1211 if (splitShadeChanged) { 1212 onSplitShadeEnabledChanged(); 1213 } 1214 1215 mSplitShadeFullTransitionDistance = 1216 mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance); 1217 } 1218 onSplitShadeEnabledChanged()1219 private void onSplitShadeEnabledChanged() { 1220 mShadeLog.logSplitShadeChanged(mSplitShadeEnabled); 1221 // Reset any left over overscroll state. It is a rare corner case but can happen. 1222 mQsController.setOverScrollAmount(0); 1223 mScrimController.setNotificationsOverScrollAmount(0); 1224 mNotificationStackScrollLayoutController.setOverExpansion(0); 1225 mNotificationStackScrollLayoutController.setOverScrollAmount(0); 1226 1227 // when we switch between split shade and regular shade we want to enforce setting qs to 1228 // the default state: expanded for split shade and collapsed otherwise 1229 if (!isOnKeyguard() && mPanelExpanded) { 1230 mQsController.setExpanded(mSplitShadeEnabled); 1231 } 1232 if (isOnKeyguard() && mQsController.getExpanded() && mSplitShadeEnabled) { 1233 // In single column keyguard - when you swipe from the top - QS is fully expanded and 1234 // StatusBarState is KEYGUARD. That state doesn't make sense for split shade, 1235 // where notifications are always visible and we effectively go to fully expanded 1236 // shade, that is SHADE_LOCKED. 1237 // Also we might just be switching from regular expanded shade, so we don't want 1238 // to force state transition if it's already correct. 1239 mStatusBarStateController.setState(StatusBarState.SHADE_LOCKED, /* force= */false); 1240 } 1241 updateClockAppearance(); 1242 mQsController.updateQsState(); 1243 mNotificationStackScrollLayoutController.updateFooter(); 1244 } 1245 reInflateStub(int viewId, int stubId, int layoutId, boolean enabled)1246 private View reInflateStub(int viewId, int stubId, int layoutId, boolean enabled) { 1247 View view = mView.findViewById(viewId); 1248 if (view != null) { 1249 int index = mView.indexOfChild(view); 1250 mView.removeView(view); 1251 if (enabled) { 1252 view = mLayoutInflater.inflate(layoutId, mView, false); 1253 mView.addView(view, index); 1254 } else { 1255 // Add the stub back so we can re-inflate it again if necessary 1256 ViewStub stub = new ViewStub(mView.getContext(), layoutId); 1257 stub.setId(stubId); 1258 mView.addView(stub, index); 1259 view = null; 1260 } 1261 } else if (enabled) { 1262 // It's possible the stub was never inflated if the configuration changed 1263 ViewStub stub = mView.findViewById(stubId); 1264 view = stub.inflate(); 1265 } 1266 return view; 1267 } 1268 1269 @VisibleForTesting reInflateViews()1270 void reInflateViews() { 1271 debugLog("reInflateViews"); 1272 // Re-inflate the status view group. 1273 KeyguardStatusView keyguardStatusView = 1274 mNotificationContainerParent.findViewById(R.id.keyguard_status_view); 1275 int statusIndex = mNotificationContainerParent.indexOfChild(keyguardStatusView); 1276 mNotificationContainerParent.removeView(keyguardStatusView); 1277 keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate( 1278 R.layout.keyguard_status_view, mNotificationContainerParent, false); 1279 mNotificationContainerParent.addView(keyguardStatusView, statusIndex); 1280 // When it's reinflated, this is centered by default. If it shouldn't be, this will update 1281 // below when resources are updated. 1282 mStatusViewCentered = true; 1283 attachSplitShadeMediaPlayerContainer( 1284 keyguardStatusView.findViewById(R.id.status_view_media_container)); 1285 1286 // we need to update KeyguardStatusView constraints after reinflating it 1287 updateResources(); 1288 1289 // Re-inflate the keyguard user switcher group. 1290 updateUserSwitcherFlags(); 1291 boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled( 1292 mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)); 1293 boolean showQsUserSwitch = mKeyguardQsUserSwitchEnabled && isUserSwitcherEnabled; 1294 boolean showKeyguardUserSwitcher = 1295 !mKeyguardQsUserSwitchEnabled 1296 && mKeyguardUserSwitcherEnabled 1297 && isUserSwitcherEnabled; 1298 FrameLayout userAvatarView = (FrameLayout) reInflateStub( 1299 R.id.keyguard_qs_user_switch_view /* viewId */, 1300 R.id.keyguard_qs_user_switch_stub /* stubId */, 1301 R.layout.keyguard_qs_user_switch /* layoutId */, 1302 showQsUserSwitch /* enabled */); 1303 KeyguardUserSwitcherView keyguardUserSwitcherView = 1304 (KeyguardUserSwitcherView) reInflateStub( 1305 R.id.keyguard_user_switcher_view /* viewId */, 1306 R.id.keyguard_user_switcher_stub /* stubId */, 1307 R.layout.keyguard_user_switcher /* layoutId */, 1308 showKeyguardUserSwitcher /* enabled */); 1309 1310 updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView, 1311 keyguardUserSwitcherView); 1312 1313 // Update keyguard bottom area 1314 int index = mView.indexOfChild(mKeyguardBottomArea); 1315 mView.removeView(mKeyguardBottomArea); 1316 KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea; 1317 setKeyguardBottomArea(mKeyguardBottomAreaViewControllerProvider.get().getView()); 1318 mKeyguardBottomArea.initFrom(oldBottomArea); 1319 mView.addView(mKeyguardBottomArea, index); 1320 initBottomArea(); 1321 mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea); 1322 mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(), 1323 mStatusBarStateController.getInterpolatedDozeAmount()); 1324 1325 mKeyguardStatusViewController.setKeyguardStatusViewVisibility( 1326 mBarState, 1327 false, 1328 false, 1329 mBarState); 1330 if (mKeyguardQsUserSwitchController != null) { 1331 mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility( 1332 mBarState, 1333 false, 1334 false, 1335 mBarState); 1336 } 1337 if (mKeyguardUserSwitcherController != null) { 1338 mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( 1339 mBarState, 1340 false, 1341 false, 1342 mBarState); 1343 } 1344 setKeyguardBottomAreaVisibility(mBarState, false); 1345 1346 mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView)); 1347 mNotificationPanelUnfoldAnimationController.ifPresent(u -> u.setup(mView)); 1348 } 1349 attachSplitShadeMediaPlayerContainer(FrameLayout container)1350 private void attachSplitShadeMediaPlayerContainer(FrameLayout container) { 1351 mKeyguardMediaController.attachSplitShadeContainer(container); 1352 } 1353 initBottomArea()1354 private void initBottomArea() { 1355 mKeyguardBottomArea.init( 1356 mKeyguardBottomAreaViewModel, 1357 mFalsingManager, 1358 mLockIconViewController, 1359 stringResourceId -> 1360 mKeyguardIndicationController.showTransientIndication(stringResourceId), 1361 mVibratorHelper); 1362 } 1363 1364 @VisibleForTesting setMaxDisplayedNotifications(int maxAllowed)1365 void setMaxDisplayedNotifications(int maxAllowed) { 1366 mMaxAllowedKeyguardNotifications = maxAllowed; 1367 } 1368 1369 @VisibleForTesting isFlinging()1370 boolean isFlinging() { 1371 return mIsFlinging; 1372 } 1373 updateMaxDisplayedNotifications(boolean recompute)1374 private void updateMaxDisplayedNotifications(boolean recompute) { 1375 if (recompute) { 1376 setMaxDisplayedNotifications(Math.max(computeMaxKeyguardNotifications(), 1)); 1377 } else { 1378 if (SPEW_LOGCAT) Log.d(TAG, "Skipping computeMaxKeyguardNotifications() by request"); 1379 } 1380 1381 if (getKeyguardShowing() && !mKeyguardBypassController.getBypassEnabled()) { 1382 mNotificationStackScrollLayoutController.setMaxDisplayedNotifications( 1383 mMaxAllowedKeyguardNotifications); 1384 mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug( 1385 mKeyguardNotificationBottomPadding); 1386 } else { 1387 // no max when not on the keyguard 1388 mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1); 1389 mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(-1f); 1390 } 1391 } 1392 shouldAvoidChangingNotificationsCount()1393 private boolean shouldAvoidChangingNotificationsCount() { 1394 return mHintAnimationRunning || mUnlockedScreenOffAnimationController.isAnimationPlaying(); 1395 } 1396 setKeyguardBottomArea(KeyguardBottomAreaView keyguardBottomArea)1397 private void setKeyguardBottomArea(KeyguardBottomAreaView keyguardBottomArea) { 1398 mKeyguardBottomArea = keyguardBottomArea; 1399 mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea); 1400 } 1401 setOpenCloseListener(OpenCloseListener openCloseListener)1402 void setOpenCloseListener(OpenCloseListener openCloseListener) { 1403 mOpenCloseListener = openCloseListener; 1404 } 1405 setTrackingStartedListener(TrackingStartedListener trackingStartedListener)1406 void setTrackingStartedListener(TrackingStartedListener trackingStartedListener) { 1407 mTrackingStartedListener = trackingStartedListener; 1408 } 1409 updateGestureExclusionRect()1410 private void updateGestureExclusionRect() { 1411 Rect exclusionRect = calculateGestureExclusionRect(); 1412 mView.setSystemGestureExclusionRects(exclusionRect.isEmpty() ? Collections.emptyList() 1413 : Collections.singletonList(exclusionRect)); 1414 } 1415 calculateGestureExclusionRect()1416 private Rect calculateGestureExclusionRect() { 1417 Rect exclusionRect = null; 1418 Region touchableRegion = mStatusBarTouchableRegionManager.calculateTouchableRegion(); 1419 if (isFullyCollapsed() && touchableRegion != null) { 1420 // Note: The manager also calculates the non-pinned touchable region 1421 exclusionRect = touchableRegion.getBounds(); 1422 } 1423 return exclusionRect != null ? exclusionRect : EMPTY_RECT; 1424 } 1425 setIsFullWidth(boolean isFullWidth)1426 private void setIsFullWidth(boolean isFullWidth) { 1427 mIsFullWidth = isFullWidth; 1428 mScrimController.setClipsQsScrim(isFullWidth); 1429 mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth); 1430 mQsController.setNotificationPanelFullWidth(isFullWidth); 1431 } 1432 1433 /** 1434 * Positions the clock and notifications dynamically depending on how many notifications are 1435 * showing. 1436 */ positionClockAndNotifications()1437 void positionClockAndNotifications() { 1438 positionClockAndNotifications(false /* forceUpdate */); 1439 } 1440 1441 /** 1442 * Positions the clock and notifications dynamically depending on how many notifications are 1443 * showing. 1444 * 1445 * @param forceClockUpdate Should the clock be updated even when not on keyguard 1446 */ positionClockAndNotifications(boolean forceClockUpdate)1447 private void positionClockAndNotifications(boolean forceClockUpdate) { 1448 boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending(); 1449 int stackScrollerPadding; 1450 boolean onKeyguard = isOnKeyguard(); 1451 1452 if (onKeyguard || forceClockUpdate) { 1453 updateClockAppearance(); 1454 } 1455 if (!onKeyguard) { 1456 if (mSplitShadeEnabled) { 1457 // Quick settings are not on the top of the notifications 1458 // when in split shade mode (they are on the left side), 1459 // so we should not add a padding for them 1460 stackScrollerPadding = 0; 1461 } else { 1462 stackScrollerPadding = mQsController.getUnlockedStackScrollerPadding(); 1463 } 1464 } else { 1465 stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded; 1466 } 1467 1468 mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding); 1469 1470 mStackScrollerMeasuringPass++; 1471 requestScrollerTopPaddingUpdate(animate); 1472 mStackScrollerMeasuringPass = 0; 1473 mAnimateNextPositionUpdate = false; 1474 } 1475 updateClockAppearance()1476 private void updateClockAppearance() { 1477 int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard; 1478 boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); 1479 boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange(); 1480 mKeyguardStatusViewController.displayClock(computeDesiredClockSize(), 1481 shouldAnimateClockChange); 1482 updateKeyguardStatusViewAlignment(/* animate= */true); 1483 int userSwitcherHeight = mKeyguardQsUserSwitchController != null 1484 ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0; 1485 if (mKeyguardUserSwitcherController != null) { 1486 userSwitcherHeight = mKeyguardUserSwitcherController.getHeight(); 1487 } 1488 float expandedFraction = 1489 mScreenOffAnimationController.shouldExpandNotifications() 1490 ? 1.0f : getExpandedFraction(); 1491 float darkAmount = 1492 mScreenOffAnimationController.shouldExpandNotifications() 1493 ? 1.0f : mInterpolatedDarkAmount; 1494 1495 float udfpsAodTopLocation = -1f; 1496 if (mUpdateMonitor.isUdfpsEnrolled() && mAuthController.getUdfpsProps().size() > 0) { 1497 FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0); 1498 final SensorLocationInternal location = props.getLocation(); 1499 udfpsAodTopLocation = location.sensorLocationY - location.sensorRadius 1500 - mUdfpsMaxYBurnInOffset; 1501 } 1502 1503 mClockPositionAlgorithm.setup( 1504 mStatusBarHeaderHeightKeyguard, 1505 expandedFraction, 1506 mKeyguardStatusViewController.getLockscreenHeight(), 1507 userSwitcherHeight, 1508 userSwitcherPreferredY, 1509 darkAmount, mOverStretchAmount, 1510 bypassEnabled, 1511 mQsController.getUnlockedStackScrollerPadding(), 1512 mQsController.computeExpansionFraction(), 1513 mDisplayTopInset, 1514 mSplitShadeEnabled, 1515 udfpsAodTopLocation, 1516 mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard), 1517 mKeyguardStatusViewController.isClockTopAligned()); 1518 mClockPositionAlgorithm.run(mClockPositionResult); 1519 mKeyguardBottomAreaInteractor.setClockPosition( 1520 mClockPositionResult.clockX, mClockPositionResult.clockY); 1521 boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending(); 1522 boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange; 1523 mKeyguardStatusViewController.updatePosition( 1524 mClockPositionResult.clockX, mClockPositionResult.clockY, 1525 mClockPositionResult.clockScale, animateClock); 1526 if (mKeyguardQsUserSwitchController != null) { 1527 mKeyguardQsUserSwitchController.updatePosition( 1528 mClockPositionResult.clockX, 1529 mClockPositionResult.userSwitchY, 1530 animateClock); 1531 } 1532 if (mKeyguardUserSwitcherController != null) { 1533 mKeyguardUserSwitcherController.updatePosition( 1534 mClockPositionResult.clockX, 1535 mClockPositionResult.userSwitchY, 1536 animateClock); 1537 } 1538 updateNotificationTranslucency(); 1539 updateClock(); 1540 } 1541 getClockPositionResult()1542 public KeyguardClockPositionAlgorithm.Result getClockPositionResult() { 1543 return mClockPositionResult; 1544 } 1545 1546 @ClockSize computeDesiredClockSize()1547 private int computeDesiredClockSize() { 1548 if (mSplitShadeEnabled) { 1549 return computeDesiredClockSizeForSplitShade(); 1550 } 1551 return computeDesiredClockSizeForSingleShade(); 1552 } 1553 1554 @ClockSize computeDesiredClockSizeForSingleShade()1555 private int computeDesiredClockSizeForSingleShade() { 1556 if (hasVisibleNotifications()) { 1557 return SMALL; 1558 } 1559 return LARGE; 1560 } 1561 1562 @ClockSize computeDesiredClockSizeForSplitShade()1563 private int computeDesiredClockSizeForSplitShade() { 1564 // Media is not visible to the user on AOD. 1565 boolean isMediaVisibleToUser = 1566 mMediaDataManager.hasActiveMediaOrRecommendation() && !isOnAod(); 1567 if (isMediaVisibleToUser) { 1568 // When media is visible, it overlaps with the large clock. Use small clock instead. 1569 return SMALL; 1570 } 1571 return LARGE; 1572 } 1573 updateKeyguardStatusViewAlignment(boolean animate)1574 private void updateKeyguardStatusViewAlignment(boolean animate) { 1575 boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered(); 1576 if (mStatusViewCentered != shouldBeCentered) { 1577 mStatusViewCentered = shouldBeCentered; 1578 ConstraintSet constraintSet = new ConstraintSet(); 1579 constraintSet.clone(mNotificationContainerParent); 1580 int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline; 1581 constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END); 1582 if (animate) { 1583 mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); 1584 ChangeBounds transition = new ChangeBounds(); 1585 if (mSplitShadeEnabled) { 1586 // Excluding media from the transition on split-shade, as it doesn't transition 1587 // horizontally properly. 1588 transition.excludeTarget(R.id.status_view_media_container, true); 1589 } 1590 1591 transition.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 1592 transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); 1593 1594 ClockAnimations clockAnims = mKeyguardStatusViewController.getClockAnimations(); 1595 boolean customClockAnimation = clockAnims != null 1596 && clockAnims.getHasCustomPositionUpdatedAnimation(); 1597 1598 if (mFeatureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION) && customClockAnimation) { 1599 // Find the clock, so we can exclude it from this transition. 1600 FrameLayout clockContainerView = 1601 mView.findViewById(R.id.lockscreen_clock_view_large); 1602 1603 // The clock container can sometimes be null. If it is, just fall back to the 1604 // old animation rather than setting up the custom animations. 1605 if (clockContainerView == null || clockContainerView.getChildCount() == 0) { 1606 transition.addListener(mKeyguardStatusAlignmentTransitionListener); 1607 TransitionManager.beginDelayedTransition( 1608 mNotificationContainerParent, transition); 1609 } else { 1610 View clockView = clockContainerView.getChildAt(0); 1611 1612 transition.excludeTarget(clockView, /* exclude= */ true); 1613 1614 TransitionSet set = new TransitionSet(); 1615 set.addTransition(transition); 1616 1617 SplitShadeTransitionAdapter adapter = 1618 new SplitShadeTransitionAdapter(mKeyguardStatusViewController); 1619 1620 // Use linear here, so the actual clock can pick its own interpolator. 1621 adapter.setInterpolator(Interpolators.LINEAR); 1622 adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION); 1623 adapter.addTarget(clockView); 1624 set.addTransition(adapter); 1625 set.addListener(mKeyguardStatusAlignmentTransitionListener); 1626 TransitionManager.beginDelayedTransition(mNotificationContainerParent, set); 1627 } 1628 } else { 1629 transition.addListener(mKeyguardStatusAlignmentTransitionListener); 1630 TransitionManager.beginDelayedTransition( 1631 mNotificationContainerParent, transition); 1632 } 1633 } 1634 1635 constraintSet.applyTo(mNotificationContainerParent); 1636 } 1637 mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(mStatusViewCentered)); 1638 } 1639 shouldKeyguardStatusViewBeCentered()1640 private boolean shouldKeyguardStatusViewBeCentered() { 1641 if (mSplitShadeEnabled) { 1642 return shouldKeyguardStatusViewBeCenteredInSplitShade(); 1643 } 1644 return true; 1645 } 1646 shouldKeyguardStatusViewBeCenteredInSplitShade()1647 private boolean shouldKeyguardStatusViewBeCenteredInSplitShade() { 1648 if (!hasVisibleNotifications()) { 1649 // No notifications visible. It is safe to have the clock centered as there will be no 1650 // overlap. 1651 return true; 1652 } 1653 if (hasPulsingNotifications()) { 1654 // Pulsing notification appears on the right. Move clock left to avoid overlap. 1655 return false; 1656 } 1657 if (mWillPlayDelayedDozeAmountAnimation) { 1658 return true; 1659 } 1660 // "Visible" notifications are actually not visible on AOD (unless pulsing), so it is safe 1661 // to center the clock without overlap. 1662 return isOnAod(); 1663 } 1664 1665 /** 1666 * Notify us that {@link NotificationWakeUpCoordinator} is going to play the doze wakeup 1667 * animation after a delay. If so, we'll keep the clock centered until that animation starts. 1668 */ setWillPlayDelayedDozeAmountAnimation(boolean willPlay)1669 public void setWillPlayDelayedDozeAmountAnimation(boolean willPlay) { 1670 if (mWillPlayDelayedDozeAmountAnimation == willPlay) return; 1671 1672 mWillPlayDelayedDozeAmountAnimation = willPlay; 1673 mWakeUpCoordinator.logDelayingClockWakeUpAnimation(willPlay); 1674 1675 // Once changing this value, see if we should move the clock. 1676 positionClockAndNotifications(); 1677 } 1678 isOnAod()1679 private boolean isOnAod() { 1680 return mDozing && mDozeParameters.getAlwaysOn(); 1681 } 1682 hasVisibleNotifications()1683 private boolean hasVisibleNotifications() { 1684 return mNotificationStackScrollLayoutController 1685 .getVisibleNotificationCount() != 0 1686 || mMediaDataManager.hasActiveMediaOrRecommendation(); 1687 } 1688 1689 /** Returns space between top of lock icon and bottom of NotificationStackScrollLayout. */ getLockIconPadding()1690 private float getLockIconPadding() { 1691 float lockIconPadding = 0f; 1692 if (mLockIconViewController.getTop() != 0f) { 1693 lockIconPadding = mNotificationStackScrollLayoutController.getBottom() 1694 - mLockIconViewController.getTop(); 1695 } 1696 return lockIconPadding; 1697 } 1698 1699 /** Returns space available to show notifications on lockscreen. */ 1700 @VisibleForTesting getVerticalSpaceForLockscreenNotifications()1701 float getVerticalSpaceForLockscreenNotifications() { 1702 final float lockIconPadding = getLockIconPadding(); 1703 1704 float bottomPadding = Math.max(lockIconPadding, 1705 Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)); 1706 mKeyguardNotificationBottomPadding = bottomPadding; 1707 1708 float staticTopPadding = mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding() 1709 // getMinStackScrollerPadding is from the top of the screen, 1710 // but we need it from the top of the NSSL. 1711 - mNotificationStackScrollLayoutController.getTop(); 1712 mKeyguardNotificationTopPadding = staticTopPadding; 1713 1714 // To debug the available space, enable debug lines in this class. If you change how the 1715 // available space is calculated, please also update those lines. 1716 final float verticalSpace = 1717 mNotificationStackScrollLayoutController.getHeight() 1718 - staticTopPadding 1719 - bottomPadding; 1720 1721 if (SPEW_LOGCAT) { 1722 Log.i(TAG, "\n"); 1723 Log.i(TAG, "staticTopPadding[" + staticTopPadding 1724 + "] = Clock.padding[" 1725 + mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding() 1726 + "] - NSSLC.top[" + mNotificationStackScrollLayoutController.getTop() 1727 + "]" 1728 ); 1729 Log.i(TAG, "bottomPadding[" + bottomPadding 1730 + "] = max(ambientIndicationBottomPadding[" + mAmbientIndicationBottomPadding 1731 + "], mIndicationBottomPadding[" + mIndicationBottomPadding 1732 + "], lockIconPadding[" + lockIconPadding 1733 + "])" 1734 ); 1735 Log.i(TAG, "verticalSpaceForNotifications[" + verticalSpace 1736 + "] = NSSL.height[" + mNotificationStackScrollLayoutController.getHeight() 1737 + "] - staticTopPadding[" + staticTopPadding 1738 + "] - bottomPadding[" + bottomPadding 1739 + "]" 1740 ); 1741 } 1742 return verticalSpace; 1743 } 1744 1745 /** Returns extra space available to show the shelf on lockscreen */ 1746 @VisibleForTesting getVerticalSpaceForLockscreenShelf()1747 float getVerticalSpaceForLockscreenShelf() { 1748 final float lockIconPadding = getLockIconPadding(); 1749 1750 final float noShelfOverlapBottomPadding = 1751 Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding); 1752 1753 final float extraSpaceForShelf = lockIconPadding - noShelfOverlapBottomPadding; 1754 1755 if (extraSpaceForShelf > 0f) { 1756 return Math.min(mNotificationShelfController.getIntrinsicHeight(), 1757 extraSpaceForShelf); 1758 } 1759 return 0f; 1760 } 1761 1762 /** 1763 * @return Maximum number of notifications that can fit on keyguard. 1764 */ 1765 @VisibleForTesting computeMaxKeyguardNotifications()1766 int computeMaxKeyguardNotifications() { 1767 if (mAmbientState.getFractionToShade() > 0) { 1768 if (SPEW_LOGCAT) { 1769 Log.v(TAG, "Internally skipping computeMaxKeyguardNotifications()" 1770 + " fractionToShade=" + mAmbientState.getFractionToShade() 1771 ); 1772 } 1773 return mMaxAllowedKeyguardNotifications; 1774 } 1775 return mNotificationStackSizeCalculator.computeMaxKeyguardNotifications( 1776 mNotificationStackScrollLayoutController.getView(), 1777 getVerticalSpaceForLockscreenNotifications(), 1778 getVerticalSpaceForLockscreenShelf(), 1779 mNotificationShelfController.getIntrinsicHeight() 1780 ); 1781 } 1782 updateClock()1783 private void updateClock() { 1784 if (mIsOcclusionTransitionRunning) { 1785 return; 1786 } 1787 float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha; 1788 mKeyguardStatusViewController.setAlpha(alpha); 1789 mKeyguardStatusViewController 1790 .setTranslationY(mKeyguardOnlyTransitionTranslationY, /* excludeMedia= */true); 1791 1792 if (mKeyguardQsUserSwitchController != null) { 1793 mKeyguardQsUserSwitchController.setAlpha(alpha); 1794 } 1795 if (mKeyguardUserSwitcherController != null) { 1796 mKeyguardUserSwitcherController.setAlpha(alpha); 1797 } 1798 } 1799 animateToFullShade(long delay)1800 public void animateToFullShade(long delay) { 1801 mNotificationStackScrollLayoutController.goToFullShade(delay); 1802 mView.requestLayout(); 1803 mAnimateNextPositionUpdate = true; 1804 } 1805 1806 /** Animate QS closing. */ animateCloseQs(boolean animateAway)1807 public void animateCloseQs(boolean animateAway) { 1808 if (mSplitShadeEnabled) { 1809 collapsePanel(true, false, 1.0f); 1810 } else { 1811 mQsController.animateCloseQs(animateAway); 1812 } 1813 1814 } 1815 resetViews(boolean animate)1816 public void resetViews(boolean animate) { 1817 mGutsManager.closeAndSaveGuts(true /* leavebehind */, true /* force */, 1818 true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */); 1819 if (animate && !isFullyCollapsed()) { 1820 animateCloseQs(true); 1821 } else { 1822 closeQsIfPossible(); 1823 } 1824 mNotificationStackScrollLayoutController.setOverScrollAmount(0f, true /* onTop */, animate, 1825 !animate /* cancelAnimators */); 1826 mNotificationStackScrollLayoutController.resetScrollPosition(); 1827 } 1828 1829 /** Collapses the panel. */ collapsePanel(boolean animate, boolean delayed, float speedUpFactor)1830 public void collapsePanel(boolean animate, boolean delayed, float speedUpFactor) { 1831 boolean waiting = false; 1832 if (animate && !isFullyCollapsed()) { 1833 collapse(delayed, speedUpFactor); 1834 waiting = true; 1835 } else { 1836 resetViews(false /* animate */); 1837 mShadeHeightLogger.logFunctionCall("collapsePanel"); 1838 setExpandedFraction(0); // just in case 1839 } 1840 if (!waiting) { 1841 // it's possible that nothing animated, so we replicate the termination 1842 // conditions of panelExpansionChanged here 1843 // TODO(b/200063118): This can likely go away in a future refactor CL. 1844 getShadeExpansionStateManager().updateState(STATE_CLOSED); 1845 } 1846 } 1847 collapse(boolean delayed, float speedUpFactor)1848 public void collapse(boolean delayed, float speedUpFactor) { 1849 if (!canPanelBeCollapsed()) { 1850 return; 1851 } 1852 1853 if (mQsController.getExpanded()) { 1854 mQsController.setExpandImmediate(true); 1855 setShowShelfOnly(true); 1856 } 1857 debugLog("collapse: %s", this); 1858 if (canPanelBeCollapsed()) { 1859 cancelHeightAnimator(); 1860 notifyExpandingStarted(); 1861 1862 // Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state. 1863 setClosing(true); 1864 if (delayed) { 1865 mNextCollapseSpeedUpFactor = speedUpFactor; 1866 this.mView.postDelayed(mFlingCollapseRunnable, 120); 1867 } else { 1868 fling(0, false /* expand */, speedUpFactor, false /* expandBecauseOfFalsing */); 1869 } 1870 } 1871 } 1872 setShowShelfOnly(boolean shelfOnly)1873 private void setShowShelfOnly(boolean shelfOnly) { 1874 mNotificationStackScrollLayoutController.setShouldShowShelfOnly( 1875 shelfOnly && !mSplitShadeEnabled); 1876 } 1877 1878 @VisibleForTesting cancelHeightAnimator()1879 void cancelHeightAnimator() { 1880 if (mHeightAnimator != null) { 1881 if (mHeightAnimator.isRunning()) { 1882 mPanelUpdateWhenAnimatorEnds = false; 1883 } 1884 mHeightAnimator.cancel(); 1885 } 1886 endClosing(); 1887 } 1888 cancelAnimation()1889 public void cancelAnimation() { 1890 mView.animate().cancel(); 1891 } 1892 expandWithQs()1893 public void expandWithQs() { 1894 if (mQsController.isExpansionEnabled()) { 1895 mQsController.setExpandImmediate(true); 1896 setShowShelfOnly(true); 1897 } 1898 if (mSplitShadeEnabled && isOnKeyguard()) { 1899 // It's a special case as this method is likely to not be initiated by finger movement 1900 // but rather called from adb shell or accessibility service. 1901 // We're using LockscreenShadeTransitionController because on lockscreen that's the 1902 // source of truth for all shade motion. Not using it would make part of state to be 1903 // outdated and will cause bugs. Ideally we'd use this controller also for non-split 1904 // case but currently motion in portrait looks worse than when using flingSettings. 1905 // TODO: make below function transitioning smoothly also in portrait with null target 1906 mLockscreenShadeTransitionController.goToLockedShade( 1907 /* expandedView= */null, /* needsQSAnimation= */true); 1908 } else if (isFullyCollapsed()) { 1909 expand(true /* animate */); 1910 } else { 1911 mQsController.traceQsJank(true /* startTracing */, false /* wasCancelled */); 1912 mQsController.flingQs(0, FLING_EXPAND); 1913 } 1914 } 1915 1916 /** 1917 * Expand shade so that notifications are visible. 1918 * Non-split shade: just expanding shade or collapsing QS when they're expanded. 1919 * Split shade: only expanding shade, notifications are always visible 1920 * 1921 * Called when `adb shell cmd statusbar expand-notifications` is executed. 1922 */ expandShadeToNotifications()1923 public void expandShadeToNotifications() { 1924 if (mSplitShadeEnabled && (isShadeFullyOpen() || isExpanding())) { 1925 return; 1926 } 1927 if (mQsController.getExpanded()) { 1928 mQsController.flingQs(0, FLING_COLLAPSE); 1929 } else { 1930 expand(true /* animate */); 1931 } 1932 } 1933 fling(float vel)1934 private void fling(float vel) { 1935 if (mGestureRecorder != null) { 1936 mGestureRecorder.tag("fling " + ((vel > 0) ? "open" : "closed"), 1937 "notifications,v=" + vel); 1938 } 1939 fling(vel, true, 1.0f /* collapseSpeedUpFactor */, false); 1940 } 1941 1942 @VisibleForTesting flingToHeight(float vel, boolean expand, float target, float collapseSpeedUpFactor, boolean expandBecauseOfFalsing)1943 void flingToHeight(float vel, boolean expand, float target, 1944 float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) { 1945 mQsController.setLastShadeFlingWasExpanding(expand); 1946 mHeadsUpTouchHelper.notifyFling(!expand); 1947 mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */); 1948 setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f); 1949 mNotificationStackScrollLayoutController.setPanelFlinging(true); 1950 if (target == mExpandedHeight && mOverExpansion == 0.0f) { 1951 // We're at the target and didn't fling and there's no overshoot 1952 onFlingEnd(false /* cancelled */); 1953 return; 1954 } 1955 mIsFlinging = true; 1956 // we want to perform an overshoot animation when flinging open 1957 final boolean addOverscroll = 1958 expand 1959 && mStatusBarStateController.getState() != KEYGUARD 1960 && mOverExpansion == 0.0f 1961 && vel >= 0; 1962 final boolean shouldSpringBack = addOverscroll || (mOverExpansion != 0.0f && expand); 1963 float overshootAmount = 0.0f; 1964 if (addOverscroll) { 1965 // Let's overshoot depending on the amount of velocity 1966 overshootAmount = MathUtils.lerp( 1967 0.2f, 1968 1.0f, 1969 MathUtils.saturate(vel 1970 / (this.mFlingAnimationUtils.getHighVelocityPxPerSecond() 1971 * FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT))); 1972 overshootAmount += mOverExpansion / mPanelFlingOvershootAmount; 1973 } 1974 ValueAnimator animator = createHeightAnimator(target, overshootAmount); 1975 if (expand) { 1976 maybeVibrateOnOpening(true /* openingWithTouch */); 1977 if (expandBecauseOfFalsing && vel < 0) { 1978 vel = 0; 1979 } 1980 this.mFlingAnimationUtils.apply(animator, mExpandedHeight, 1981 target + overshootAmount * mPanelFlingOvershootAmount, vel, 1982 this.mView.getHeight()); 1983 if (vel == 0) { 1984 animator.setDuration(SHADE_OPEN_SPRING_OUT_DURATION); 1985 } 1986 } else { 1987 mHasVibratedOnOpen = false; 1988 if (shouldUseDismissingAnimation()) { 1989 if (vel == 0) { 1990 animator.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED); 1991 long duration = (long) (200 + mExpandedHeight / this.mView.getHeight() * 100); 1992 animator.setDuration(duration); 1993 } else { 1994 mFlingAnimationUtilsDismissing.apply(animator, mExpandedHeight, target, vel, 1995 this.mView.getHeight()); 1996 } 1997 } else { 1998 mFlingAnimationUtilsClosing.apply( 1999 animator, mExpandedHeight, target, vel, this.mView.getHeight()); 2000 } 2001 2002 // Make it shorter if we run a canned animation 2003 if (vel == 0) { 2004 animator.setDuration((long) (animator.getDuration() / collapseSpeedUpFactor)); 2005 } 2006 if (mFixedDuration != NO_FIXED_DURATION) { 2007 animator.setDuration(mFixedDuration); 2008 } 2009 } 2010 animator.addListener(new AnimatorListenerAdapter() { 2011 private boolean mCancelled; 2012 2013 @Override 2014 public void onAnimationStart(Animator animation) { 2015 if (!mStatusBarStateController.isDozing()) { 2016 mQsController.beginJankMonitoring(isFullyCollapsed()); 2017 } 2018 } 2019 2020 @Override 2021 public void onAnimationCancel(Animator animation) { 2022 mCancelled = true; 2023 } 2024 2025 @Override 2026 public void onAnimationEnd(Animator animation) { 2027 if (shouldSpringBack && !mCancelled) { 2028 // After the shade is flung open to an overscrolled state, spring back 2029 // the shade by reducing section padding to 0. 2030 springBack(); 2031 } else { 2032 onFlingEnd(mCancelled); 2033 } 2034 } 2035 }); 2036 setAnimator(animator); 2037 animator.start(); 2038 } 2039 2040 @VisibleForTesting onFlingEnd(boolean cancelled)2041 void onFlingEnd(boolean cancelled) { 2042 mIsFlinging = false; 2043 // No overshoot when the animation ends 2044 setOverExpansionInternal(0, false /* isFromGesture */); 2045 setAnimator(null); 2046 mKeyguardStateController.notifyPanelFlingEnd(); 2047 if (!cancelled) { 2048 mQsController.endJankMonitoring(); 2049 notifyExpandingFinished(); 2050 } else { 2051 mQsController.cancelJankMonitoring(); 2052 } 2053 updatePanelExpansionAndVisibility(); 2054 mNotificationStackScrollLayoutController.setPanelFlinging(false); 2055 } 2056 isInContentBounds(float x, float y)2057 private boolean isInContentBounds(float x, float y) { 2058 float stackScrollerX = mNotificationStackScrollLayoutController.getX(); 2059 return !mNotificationStackScrollLayoutController 2060 .isBelowLastNotification(x - stackScrollerX, y) 2061 && stackScrollerX < x 2062 && x < stackScrollerX + mNotificationStackScrollLayoutController.getWidth(); 2063 } 2064 initDownStates(MotionEvent event)2065 private void initDownStates(MotionEvent event) { 2066 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 2067 mDozingOnDown = mDozing; 2068 mDownX = event.getX(); 2069 mDownY = event.getY(); 2070 mCollapsedOnDown = isFullyCollapsed(); 2071 mQsController.setCollapsedOnDown(mCollapsedOnDown); 2072 mIsPanelCollapseOnQQS = mQsController.canPanelCollapseOnQQS(mDownX, mDownY); 2073 mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp(); 2074 mAllowExpandForSmallExpansion = mExpectingSynthesizedDown; 2075 mTouchSlopExceededBeforeDown = mExpectingSynthesizedDown; 2076 // When false, down but not synthesized motion event. 2077 mLastEventSynthesizedDown = mExpectingSynthesizedDown; 2078 mLastDownEvents.insert( 2079 event.getEventTime(), 2080 mDownX, 2081 mDownY, 2082 mQsController.updateAndGetTouchAboveFalsingThreshold(), 2083 mDozingOnDown, 2084 mCollapsedOnDown, 2085 mIsPanelCollapseOnQQS, 2086 mListenForHeadsUp, 2087 mAllowExpandForSmallExpansion, 2088 mTouchSlopExceededBeforeDown, 2089 mLastEventSynthesizedDown 2090 ); 2091 } else { 2092 // not down event at all. 2093 mLastEventSynthesizedDown = false; 2094 } 2095 } 2096 flingExpandsQs(float vel)2097 boolean flingExpandsQs(float vel) { 2098 if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) { 2099 return mQsController.computeExpansionFraction() > 0.5f; 2100 } else { 2101 return vel > 0; 2102 } 2103 } 2104 shouldExpandWhenNotFlinging()2105 private boolean shouldExpandWhenNotFlinging() { 2106 if (getExpandedFraction() > 0.5f) { 2107 return true; 2108 } 2109 if (mAllowExpandForSmallExpansion) { 2110 // When we get a touch that came over from launcher, the velocity isn't always correct 2111 // Let's err on expanding if the gesture has been reasonably slow 2112 long timeSinceDown = mSystemClock.uptimeMillis() - mDownTime; 2113 return timeSinceDown <= MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER; 2114 } 2115 return false; 2116 } 2117 getOpeningHeight()2118 private float getOpeningHeight() { 2119 return mNotificationStackScrollLayoutController.getOpeningHeight(); 2120 } 2121 getDisplayDensity()2122 float getDisplayDensity() { 2123 return mCentralSurfaces.getDisplayDensity(); 2124 } 2125 2126 /** Return whether a touch is near the gesture handle at the bottom of screen */ isInGestureNavHomeHandleArea(float x, float y)2127 public boolean isInGestureNavHomeHandleArea(float x, float y) { 2128 return mIsGestureNavigation && y > mView.getHeight() - mNavigationBarBottomHeight; 2129 } 2130 2131 /** Input focus transfer is about to happen. */ startWaitingForOpenPanelGesture()2132 public void startWaitingForOpenPanelGesture() { 2133 if (!isFullyCollapsed()) { 2134 return; 2135 } 2136 mExpectingSynthesizedDown = true; 2137 onTrackingStarted(); 2138 updatePanelExpanded(); 2139 } 2140 2141 /** 2142 * Called when this view is no longer waiting for input focus transfer. 2143 * 2144 * There are two scenarios behind this function call. First, input focus transfer 2145 * has successfully happened and this view already received synthetic DOWN event. 2146 * (mExpectingSynthesizedDown == false). Do nothing. 2147 * 2148 * Second, before input focus transfer finished, user may have lifted finger 2149 * in previous window and this window never received synthetic DOWN event. 2150 * (mExpectingSynthesizedDown == true). 2151 * In this case, we use the velocity to trigger fling event. 2152 * 2153 * @param velocity unit is in px / millis 2154 */ stopWaitingForOpenPanelGesture(boolean cancel, final float velocity)2155 public void stopWaitingForOpenPanelGesture(boolean cancel, final float velocity) { 2156 if (mExpectingSynthesizedDown) { 2157 mExpectingSynthesizedDown = false; 2158 if (cancel) { 2159 collapse(false /* delayed */, 1.0f /* speedUpFactor */); 2160 } else { 2161 // Window never will receive touch events that typically trigger haptic on open. 2162 maybeVibrateOnOpening(false /* openingWithTouch */); 2163 fling(velocity > 1f ? 1000f * velocity : 0 /* expand */); 2164 } 2165 onTrackingStopped(false); 2166 } 2167 } 2168 flingExpands(float vel, float vectorVel, float x, float y)2169 private boolean flingExpands(float vel, float vectorVel, float x, float y) { 2170 boolean expands = true; 2171 if (!this.mFalsingManager.isUnlockingDisabled()) { 2172 @Classifier.InteractionType int interactionType = y - mInitialExpandY > 0 2173 ? QUICK_SETTINGS : ( 2174 mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK); 2175 if (!isFalseTouch(x, y, interactionType)) { 2176 if (Math.abs(vectorVel) < this.mFlingAnimationUtils.getMinVelocityPxPerSecond()) { 2177 expands = shouldExpandWhenNotFlinging(); 2178 } else { 2179 expands = vel > 0; 2180 } 2181 } 2182 } 2183 2184 // If we are already running a QS expansion, make sure that we keep the panel open. 2185 if (mQsController.isExpansionAnimating()) { 2186 expands = true; 2187 } 2188 return expands; 2189 } 2190 shouldGestureWaitForTouchSlop()2191 private boolean shouldGestureWaitForTouchSlop() { 2192 if (mExpectingSynthesizedDown) { 2193 mExpectingSynthesizedDown = false; 2194 return false; 2195 } 2196 return isFullyCollapsed() || mBarState != StatusBarState.SHADE; 2197 } 2198 getFalsingThreshold()2199 int getFalsingThreshold() { 2200 float factor = mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f; 2201 return (int) (mQsController.getFalsingThreshold() * factor); 2202 } 2203 maybeAnimateBottomAreaAlpha()2204 private void maybeAnimateBottomAreaAlpha() { 2205 mBottomAreaShadeAlphaAnimator.cancel(); 2206 if (mBarState == StatusBarState.SHADE_LOCKED) { 2207 mBottomAreaShadeAlphaAnimator.setFloatValues(mBottomAreaShadeAlpha, 0.0f); 2208 mBottomAreaShadeAlphaAnimator.start(); 2209 } else { 2210 mBottomAreaShadeAlpha = 1f; 2211 } 2212 } 2213 setKeyguardBottomAreaVisibility(int statusBarState, boolean goingToFullShade)2214 private void setKeyguardBottomAreaVisibility(int statusBarState, boolean goingToFullShade) { 2215 mKeyguardBottomArea.animate().cancel(); 2216 if (goingToFullShade) { 2217 mKeyguardBottomArea.animate().alpha(0f).setStartDelay( 2218 mKeyguardStateController.getKeyguardFadingAwayDelay()).setDuration( 2219 mKeyguardStateController.getShortenedFadingAwayDuration()).setInterpolator( 2220 Interpolators.ALPHA_OUT).withEndAction( 2221 mAnimateKeyguardBottomAreaInvisibleEndRunnable).start(); 2222 } else if (statusBarState == KEYGUARD 2223 || statusBarState == StatusBarState.SHADE_LOCKED) { 2224 mKeyguardBottomArea.setVisibility(View.VISIBLE); 2225 if (!mIsOcclusionTransitionRunning) { 2226 mKeyguardBottomArea.setAlpha(1f); 2227 } 2228 } else { 2229 mKeyguardBottomArea.setVisibility(View.GONE); 2230 } 2231 } 2232 2233 /** */ getLockscreenShadeDragProgress()2234 public float getLockscreenShadeDragProgress() { 2235 // mTransitioningToFullShadeProgress > 0 means we're doing regular lockscreen to shade 2236 // transition. If that's not the case we should follow QS expansion fraction for when 2237 // user is pulling from the same top to go directly to expanded QS 2238 return mQsController.getTransitioningToFullShadeProgress() > 0 2239 ? mLockscreenShadeTransitionController.getQSDragProgress() 2240 : mQsController.computeExpansionFraction(); 2241 } 2242 determineAccessibilityPaneTitle()2243 String determineAccessibilityPaneTitle() { 2244 if (mQsController != null && mQsController.isCustomizing()) { 2245 return mResources.getString(R.string.accessibility_desc_quick_settings_edit); 2246 } else if (mQsController != null && mQsController.getExpansionHeight() != 0.0f 2247 && mQsController.getFullyExpanded()) { 2248 // Upon initialisation when we are not layouted yet we don't want to announce that we 2249 // are fully expanded, hence the != 0.0f check. 2250 if (mSplitShadeEnabled) { 2251 // In split shade, QS is expanded but it also shows notifications 2252 return mResources.getString(R.string.accessibility_desc_qs_notification_shade); 2253 } else { 2254 return mResources.getString(R.string.accessibility_desc_quick_settings); 2255 } 2256 } else if (mBarState == KEYGUARD) { 2257 return mResources.getString(R.string.accessibility_desc_lock_screen); 2258 } else { 2259 return mResources.getString(R.string.accessibility_desc_notification_shade); 2260 } 2261 } 2262 2263 /** Returns the topPadding of notifications when on keyguard not respecting QS expansion. */ getKeyguardNotificationStaticPadding()2264 public int getKeyguardNotificationStaticPadding() { 2265 if (!getKeyguardShowing()) { 2266 return 0; 2267 } 2268 if (!mKeyguardBypassController.getBypassEnabled()) { 2269 return mClockPositionResult.stackScrollerPadding; 2270 } 2271 int collapsedPosition = mHeadsUpInset; 2272 if (!mNotificationStackScrollLayoutController.isPulseExpanding()) { 2273 return collapsedPosition; 2274 } else { 2275 int expandedPosition = 2276 mClockPositionResult.stackScrollerPadding; 2277 return (int) MathUtils.lerp(collapsedPosition, expandedPosition, 2278 mNotificationStackScrollLayoutController.calculateAppearFractionBypass()); 2279 } 2280 } 2281 getKeyguardShowing()2282 public boolean getKeyguardShowing() { 2283 return mBarState == KEYGUARD; 2284 } 2285 getKeyguardNotificationTopPadding()2286 public float getKeyguardNotificationTopPadding() { 2287 return mKeyguardNotificationTopPadding; 2288 } 2289 getKeyguardNotificationBottomPadding()2290 public float getKeyguardNotificationBottomPadding() { 2291 return mKeyguardNotificationBottomPadding; 2292 } 2293 requestScrollerTopPaddingUpdate(boolean animate)2294 void requestScrollerTopPaddingUpdate(boolean animate) { 2295 mNotificationStackScrollLayoutController.updateTopPadding( 2296 mQsController.calculateNotificationsTopPadding(mIsExpanding, 2297 getKeyguardNotificationStaticPadding(), mExpandedFraction), animate); 2298 if (getKeyguardShowing() 2299 && mKeyguardBypassController.getBypassEnabled()) { 2300 // update the position of the header 2301 mQsController.updateExpansion(); 2302 } 2303 } 2304 2305 /** 2306 * Set the alpha and translationY of the keyguard elements which only show on the lockscreen, 2307 * but not in shade locked / shade. This is used when dragging down to the full shade. 2308 */ setKeyguardTransitionProgress(float keyguardAlpha, int keyguardTranslationY)2309 public void setKeyguardTransitionProgress(float keyguardAlpha, int keyguardTranslationY) { 2310 mKeyguardOnlyContentAlpha = Interpolators.ALPHA_IN.getInterpolation(keyguardAlpha); 2311 mKeyguardOnlyTransitionTranslationY = keyguardTranslationY; 2312 if (mBarState == KEYGUARD) { 2313 // If the animator is running, it's already fading out the content and this is a reset 2314 mBottomAreaShadeAlpha = mKeyguardOnlyContentAlpha; 2315 updateKeyguardBottomAreaAlpha(); 2316 } 2317 updateClock(); 2318 } 2319 2320 /** 2321 * Sets the alpha value to be set on the keyguard status bar. 2322 * 2323 * @param alpha value between 0 and 1. -1 if the value is to be reset. 2324 */ setKeyguardStatusBarAlpha(float alpha)2325 public void setKeyguardStatusBarAlpha(float alpha) { 2326 mKeyguardStatusBarViewController.setAlpha(alpha); 2327 } 2328 2329 /** */ getKeyguardOnlyContentAlpha()2330 public float getKeyguardOnlyContentAlpha() { 2331 return mKeyguardOnlyContentAlpha; 2332 } 2333 2334 @VisibleForTesting canCollapsePanelOnTouch()2335 boolean canCollapsePanelOnTouch() { 2336 if (!mQsController.getExpanded() && mBarState == KEYGUARD) { 2337 return true; 2338 } 2339 2340 if (mNotificationStackScrollLayoutController.isScrolledToBottom()) { 2341 return true; 2342 } 2343 2344 return !mSplitShadeEnabled && (mQsController.getExpanded() || mIsPanelCollapseOnQQS); 2345 } 2346 getMaxPanelHeight()2347 int getMaxPanelHeight() { 2348 int min = mStatusBarMinHeight; 2349 if (!(mBarState == KEYGUARD) 2350 && mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) { 2351 int minHeight = mQsController.getMinExpansionHeight(); 2352 min = Math.max(min, minHeight); 2353 } 2354 int maxHeight; 2355 if (mQsController.isExpandImmediate() || mQsController.getExpanded() 2356 || mIsExpanding && mQsController.getExpandedWhenExpandingStarted() 2357 || mPulsing || mSplitShadeEnabled) { 2358 maxHeight = mQsController.calculatePanelHeightExpanded( 2359 mClockPositionResult.stackScrollerPadding); 2360 } else { 2361 maxHeight = calculatePanelHeightShade(); 2362 } 2363 maxHeight = Math.max(min, maxHeight); 2364 if (maxHeight == 0) { 2365 Log.wtf(TAG, "maxPanelHeight is invalid. mOverExpansion: " 2366 + mOverExpansion + ", calculatePanelHeightQsExpanded: " 2367 + mQsController.calculatePanelHeightExpanded( 2368 mClockPositionResult.stackScrollerPadding) 2369 + ", calculatePanelHeightShade: " + calculatePanelHeightShade() 2370 + ", mStatusBarMinHeight = " + mStatusBarMinHeight 2371 + ", mQsMinExpansionHeight = " + mQsController.getMinExpansionHeight()); 2372 } 2373 return maxHeight; 2374 } 2375 isExpanding()2376 public boolean isExpanding() { 2377 return mIsExpanding; 2378 } 2379 onHeightUpdated(float expandedHeight)2380 private void onHeightUpdated(float expandedHeight) { 2381 if (expandedHeight <= 0) { 2382 mShadeLog.logExpansionChanged("onHeightUpdated: fully collapsed.", 2383 mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx); 2384 } else if (isFullyExpanded()) { 2385 mShadeLog.logExpansionChanged("onHeightUpdated: fully expanded.", 2386 mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx); 2387 } 2388 if (!mQsController.getExpanded() || mQsController.isExpandImmediate() 2389 || mIsExpanding && mQsController.getExpandedWhenExpandingStarted()) { 2390 // Updating the clock position will set the top padding which might 2391 // trigger a new panel height and re-position the clock. 2392 // This is a circular dependency and should be avoided, otherwise we'll have 2393 // a stack overflow. 2394 if (mStackScrollerMeasuringPass > 2) { 2395 debugLog("Unstable notification panel height. Aborting."); 2396 } else { 2397 positionClockAndNotifications(); 2398 } 2399 } 2400 boolean goingBetweenClosedShadeAndExpandedQs = 2401 mQsController.isGoingBetweenClosedShadeAndExpandedQs(); 2402 // in split shade we react when HUN is visible only if shade height is over HUN start 2403 // height - which means user is swiping down. Otherwise shade QS will either not show at all 2404 // with HUN movement or it will blink when touching HUN initially 2405 boolean qsShouldExpandWithHeadsUp = !mSplitShadeEnabled 2406 || (!mHeadsUpManager.isTrackingHeadsUp() || expandedHeight > mHeadsUpStartHeight); 2407 if (goingBetweenClosedShadeAndExpandedQs && qsShouldExpandWithHeadsUp) { 2408 float qsExpansionFraction; 2409 if (mSplitShadeEnabled) { 2410 qsExpansionFraction = 1; 2411 } else if (getKeyguardShowing()) { 2412 // On Keyguard, interpolate the QS expansion linearly to the panel expansion 2413 qsExpansionFraction = expandedHeight / (getMaxPanelHeight()); 2414 } else { 2415 // In Shade, interpolate linearly such that QS is closed whenever panel height is 2416 // minimum QS expansion + minStackHeight 2417 float panelHeightQsCollapsed = 2418 mNotificationStackScrollLayoutController.getIntrinsicPadding() 2419 + mNotificationStackScrollLayoutController.getLayoutMinHeight(); 2420 float panelHeightQsExpanded = mQsController.calculatePanelHeightExpanded( 2421 mClockPositionResult.stackScrollerPadding); 2422 qsExpansionFraction = (expandedHeight - panelHeightQsCollapsed) 2423 / (panelHeightQsExpanded - panelHeightQsCollapsed); 2424 } 2425 float targetHeight = mQsController.getMinExpansionHeight() + qsExpansionFraction 2426 * (mQsController.getMaxExpansionHeight() 2427 - mQsController.getMinExpansionHeight()); 2428 mQsController.setExpansionHeight(targetHeight); 2429 } 2430 updateExpandedHeight(expandedHeight); 2431 updateHeader(); 2432 updateNotificationTranslucency(); 2433 updatePanelExpanded(); 2434 updateGestureExclusionRect(); 2435 if (DEBUG_DRAWABLE) { 2436 mView.invalidate(); 2437 } 2438 } 2439 updatePanelExpanded()2440 private void updatePanelExpanded() { 2441 boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown; 2442 if (mPanelExpanded != isExpanded) { 2443 mPanelExpanded = isExpanded; 2444 mShadeExpansionStateManager.onShadeExpansionFullyChanged(isExpanded); 2445 if (!isExpanded) { 2446 mQsController.closeQsCustomizer(); 2447 } 2448 } 2449 } 2450 isPanelExpanded()2451 public boolean isPanelExpanded() { 2452 return mPanelExpanded; 2453 } 2454 calculatePanelHeightShade()2455 private int calculatePanelHeightShade() { 2456 int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin(); 2457 int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin; 2458 2459 if (mBarState == KEYGUARD) { 2460 int minKeyguardPanelBottom = mClockPositionAlgorithm.getLockscreenStatusViewHeight() 2461 + mNotificationStackScrollLayoutController.getIntrinsicContentHeight(); 2462 return Math.max(maxHeight, minKeyguardPanelBottom); 2463 } else { 2464 return maxHeight; 2465 } 2466 } 2467 updateNotificationTranslucency()2468 private void updateNotificationTranslucency() { 2469 if (mIsOcclusionTransitionRunning) { 2470 return; 2471 } 2472 float alpha = 1f; 2473 if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp 2474 && !mHeadsUpManager.hasPinnedHeadsUp()) { 2475 alpha = getFadeoutAlpha(); 2476 } 2477 if (mBarState == KEYGUARD && !mHintAnimationRunning 2478 && !mKeyguardBypassController.getBypassEnabled()) { 2479 alpha *= mClockPositionResult.clockAlpha; 2480 } 2481 mNotificationStackScrollLayoutController.setAlpha(alpha); 2482 } 2483 getFadeoutAlpha()2484 private float getFadeoutAlpha() { 2485 float alpha; 2486 if (mQsController.getMinExpansionHeight() == 0) { 2487 return 1.0f; 2488 } 2489 alpha = getExpandedHeight() / mQsController.getMinExpansionHeight(); 2490 alpha = Math.max(0, Math.min(alpha, 1)); 2491 alpha = (float) Math.pow(alpha, 0.75); 2492 return alpha; 2493 } 2494 2495 /** Hides the header when notifications are colliding with it. */ updateHeader()2496 private void updateHeader() { 2497 if (mBarState == KEYGUARD) { 2498 mKeyguardStatusBarViewController.updateViewState(); 2499 } 2500 mQsController.updateExpansion(); 2501 } 2502 updateKeyguardBottomAreaAlpha()2503 private void updateKeyguardBottomAreaAlpha() { 2504 if (mIsOcclusionTransitionRunning) { 2505 return; 2506 } 2507 // There are two possible panel expansion behaviors: 2508 // • User dragging up to unlock: we want to fade out as quick as possible 2509 // (ALPHA_EXPANSION_THRESHOLD) to avoid seeing the bouncer over the bottom area. 2510 // • User tapping on lock screen: bouncer won't be visible but panel expansion will 2511 // change due to "unlock hint animation." In this case, fading out the bottom area 2512 // would also hide the message that says "swipe to unlock," we don't want to do that. 2513 float expansionAlpha = MathUtils.map( 2514 isUnlockHintRunning() ? 0 : KeyguardBouncerConstants.ALPHA_EXPANSION_THRESHOLD, 1f, 2515 0f, 1f, 2516 getExpandedFraction()); 2517 float alpha = Math.min(expansionAlpha, 1 - mQsController.computeExpansionFraction()); 2518 alpha *= mBottomAreaShadeAlpha; 2519 mKeyguardBottomAreaInteractor.setAlpha(alpha); 2520 mLockIconViewController.setAlpha(alpha); 2521 } 2522 onExpandingFinished()2523 private void onExpandingFinished() { 2524 mNotificationStackScrollLayoutController.onExpansionStopped(); 2525 mHeadsUpManager.onExpandingFinished(); 2526 mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed()); 2527 mIsExpanding = false; 2528 mMediaHierarchyManager.setCollapsingShadeFromQS(false); 2529 mMediaHierarchyManager.setQsExpanded(mQsController.getExpanded()); 2530 if (isFullyCollapsed()) { 2531 DejankUtils.postAfterTraversal(() -> setListening(false)); 2532 2533 // Workaround b/22639032: Make sure we invalidate something because else RenderThread 2534 // thinks we are actually drawing a frame put in reality we don't, so RT doesn't go 2535 // ahead with rendering and we jank. 2536 mView.postOnAnimation( 2537 () -> mView.getParent().invalidateChild(mView, M_DUMMY_DIRTY_RECT)); 2538 } else { 2539 setListening(true); 2540 } 2541 if (mBarState != SHADE) { 2542 // updating qsExpandImmediate is done in onPanelStateChanged for unlocked shade but 2543 // on keyguard panel state is always OPEN so we need to have that extra update 2544 mQsController.setExpandImmediate(false); 2545 } 2546 setShowShelfOnly(false); 2547 mQsController.setTwoFingerExpandPossible(false); 2548 updateTrackingHeadsUp(null); 2549 mExpandingFromHeadsUp = false; 2550 setPanelScrimMinFraction(0.0f); 2551 // Reset status bar alpha so alpha can be calculated upon updating view state. 2552 setKeyguardStatusBarAlpha(-1f); 2553 } 2554 updateTrackingHeadsUp(@ullable ExpandableNotificationRow pickedChild)2555 private void updateTrackingHeadsUp(@Nullable ExpandableNotificationRow pickedChild) { 2556 mTrackedHeadsUpNotification = pickedChild; 2557 for (int i = 0; i < mTrackingHeadsUpListeners.size(); i++) { 2558 Consumer<ExpandableNotificationRow> listener = mTrackingHeadsUpListeners.get(i); 2559 listener.accept(pickedChild); 2560 } 2561 } 2562 2563 @Nullable getTrackedHeadsUpNotification()2564 public ExpandableNotificationRow getTrackedHeadsUpNotification() { 2565 return mTrackedHeadsUpNotification; 2566 } 2567 setListening(boolean listening)2568 private void setListening(boolean listening) { 2569 mKeyguardStatusBarViewController.setBatteryListening(listening); 2570 mQsController.setListening(listening); 2571 } 2572 expand(boolean animate)2573 public void expand(boolean animate) { 2574 if (isFullyCollapsed() || isCollapsing()) { 2575 mInstantExpanding = true; 2576 mAnimateAfterExpanding = animate; 2577 mUpdateFlingOnLayout = false; 2578 abortAnimations(); 2579 if (mTracking) { 2580 // The panel is expanded after this call. 2581 onTrackingStopped(true /* expands */); 2582 } 2583 if (mExpanding) { 2584 notifyExpandingFinished(); 2585 } 2586 updatePanelExpansionAndVisibility(); 2587 // Wait for window manager to pickup the change, so we know the maximum height of the 2588 // panel then. 2589 this.mView.getViewTreeObserver().addOnGlobalLayoutListener( 2590 new ViewTreeObserver.OnGlobalLayoutListener() { 2591 @Override 2592 public void onGlobalLayout() { 2593 if (!mInstantExpanding) { 2594 mView.getViewTreeObserver().removeOnGlobalLayoutListener( 2595 this); 2596 return; 2597 } 2598 if (mCentralSurfaces.getNotificationShadeWindowView() 2599 .isVisibleToUser()) { 2600 mView.getViewTreeObserver().removeOnGlobalLayoutListener( 2601 this); 2602 if (mAnimateAfterExpanding) { 2603 notifyExpandingStarted(); 2604 mQsController.beginJankMonitoring(isFullyCollapsed()); 2605 fling(0 /* expand */); 2606 } else { 2607 mShadeHeightLogger.logFunctionCall("expand"); 2608 setExpandedFraction(1f); 2609 } 2610 mInstantExpanding = false; 2611 } 2612 } 2613 }); 2614 // Make sure a layout really happens. 2615 this.mView.requestLayout(); 2616 } 2617 2618 setListening(true); 2619 } 2620 2621 @VisibleForTesting setTouchSlopExceeded(boolean isTouchSlopExceeded)2622 void setTouchSlopExceeded(boolean isTouchSlopExceeded) { 2623 mTouchSlopExceeded = isTouchSlopExceeded; 2624 } 2625 setOverExpansion(float overExpansion)2626 public void setOverExpansion(float overExpansion) { 2627 if (overExpansion == mOverExpansion) { 2628 return; 2629 } 2630 mOverExpansion = overExpansion; 2631 if (mSplitShadeEnabled) { 2632 mQsController.setOverScrollAmount((int) overExpansion); 2633 mScrimController.setNotificationsOverScrollAmount((int) overExpansion); 2634 } else { 2635 // Translating the quick settings by half the overexpansion to center it in the 2636 // background frame 2637 mQsController.updateQsFrameTranslation(); 2638 } 2639 mNotificationStackScrollLayoutController.setOverExpansion(overExpansion); 2640 } 2641 falsingAdditionalTapRequired()2642 private void falsingAdditionalTapRequired() { 2643 if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) { 2644 mTapAgainViewController.show(); 2645 } else { 2646 mKeyguardIndicationController.showTransientIndication( 2647 R.string.notification_tap_again); 2648 } 2649 2650 if (!mStatusBarStateController.isDozing()) { 2651 mVibratorHelper.vibrate( 2652 Process.myUid(), 2653 mView.getContext().getPackageName(), 2654 ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT, 2655 "falsing-additional-tap-required", 2656 TOUCH_VIBRATION_ATTRIBUTES); 2657 } 2658 } 2659 onTrackingStarted()2660 private void onTrackingStarted() { 2661 mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen()); 2662 endClosing(); 2663 mTracking = true; 2664 mTrackingStartedListener.onTrackingStarted(); 2665 notifyExpandingStarted(); 2666 updatePanelExpansionAndVisibility(); 2667 mScrimController.onTrackingStarted(); 2668 if (mQsController.getFullyExpanded()) { 2669 mQsController.setExpandImmediate(true); 2670 setShowShelfOnly(true); 2671 } 2672 mNotificationStackScrollLayoutController.onPanelTrackingStarted(); 2673 cancelPendingPanelCollapse(); 2674 } 2675 onTrackingStopped(boolean expand)2676 private void onTrackingStopped(boolean expand) { 2677 mFalsingCollector.onTrackingStopped(); 2678 mTracking = false; 2679 updatePanelExpansionAndVisibility(); 2680 if (expand) { 2681 mNotificationStackScrollLayoutController.setOverScrollAmount(0.0f, true /* onTop */, 2682 true /* animate */); 2683 } 2684 mNotificationStackScrollLayoutController.onPanelTrackingStopped(); 2685 2686 // If we unlocked from a swipe, the user's finger might still be down after the 2687 // unlock animation ends. We need to wait until ACTION_UP to enable blurs again. 2688 mDepthController.setBlursDisabledForUnlock(false); 2689 } 2690 updateMaxHeadsUpTranslation()2691 private void updateMaxHeadsUpTranslation() { 2692 mNotificationStackScrollLayoutController.setHeadsUpBoundaries( 2693 mView.getHeight(), mNavigationBarBottomHeight); 2694 } 2695 2696 @VisibleForTesting startUnlockHintAnimation()2697 void startUnlockHintAnimation() { 2698 if (mPowerManager.isPowerSaveMode() || mAmbientState.getDozeAmount() > 0f) { 2699 onUnlockHintStarted(); 2700 onUnlockHintFinished(); 2701 return; 2702 } 2703 2704 // We don't need to hint the user if an animation is already running or the user is changing 2705 // the expansion. 2706 if (mHeightAnimator != null || mTracking) { 2707 return; 2708 } 2709 notifyExpandingStarted(); 2710 startUnlockHintAnimationPhase1(() -> { 2711 notifyExpandingFinished(); 2712 onUnlockHintFinished(); 2713 mHintAnimationRunning = false; 2714 }); 2715 onUnlockHintStarted(); 2716 mHintAnimationRunning = true; 2717 } 2718 2719 @VisibleForTesting onUnlockHintFinished()2720 void onUnlockHintFinished() { 2721 // Delay the reset a bit so the user can read the text. 2722 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS); 2723 mScrimController.setExpansionAffectsAlpha(true); 2724 mNotificationStackScrollLayoutController.setUnlockHintRunning(false); 2725 } 2726 2727 @VisibleForTesting onUnlockHintStarted()2728 void onUnlockHintStarted() { 2729 mFalsingCollector.onUnlockHintStarted(); 2730 mKeyguardIndicationController.showActionToUnlock(); 2731 mScrimController.setExpansionAffectsAlpha(false); 2732 mNotificationStackScrollLayoutController.setUnlockHintRunning(true); 2733 } 2734 shouldUseDismissingAnimation()2735 private boolean shouldUseDismissingAnimation() { 2736 return mBarState != StatusBarState.SHADE && (mKeyguardStateController.canDismissLockScreen() 2737 || !isTracking()); 2738 } 2739 2740 @VisibleForTesting getMaxPanelTransitionDistance()2741 int getMaxPanelTransitionDistance() { 2742 // Traditionally the value is based on the number of notifications. On split-shade, we want 2743 // the required distance to be a specific and constant value, to make sure the expansion 2744 // motion has the expected speed. We also only want this on non-lockscreen for now. 2745 if (mSplitShadeEnabled && mBarState == SHADE) { 2746 boolean transitionFromHeadsUp = (mHeadsUpManager != null 2747 && mHeadsUpManager.isTrackingHeadsUp()) || mExpandingFromHeadsUp; 2748 // heads-up starting height is too close to mSplitShadeFullTransitionDistance and 2749 // when dragging HUN transition is already 90% complete. It makes shade become 2750 // immediately visible when starting to drag. We want to set distance so that 2751 // nothing is immediately visible when dragging (important for HUN swipe up motion) - 2752 // 0.4 expansion fraction is a good starting point. 2753 if (transitionFromHeadsUp) { 2754 double maxDistance = Math.max(mSplitShadeFullTransitionDistance, 2755 mHeadsUpStartHeight * 2.5); 2756 return (int) Math.min(getMaxPanelHeight(), maxDistance); 2757 } else { 2758 return mSplitShadeFullTransitionDistance; 2759 } 2760 } else { 2761 return getMaxPanelHeight(); 2762 } 2763 } 2764 setIsLaunchAnimationRunning(boolean running)2765 public void setIsLaunchAnimationRunning(boolean running) { 2766 boolean wasRunning = mIsLaunchAnimationRunning; 2767 mIsLaunchAnimationRunning = running; 2768 if (wasRunning != mIsLaunchAnimationRunning) { 2769 mShadeExpansionStateManager.notifyLaunchingActivityChanged(running); 2770 } 2771 } 2772 2773 @VisibleForTesting setClosing(boolean isClosing)2774 void setClosing(boolean isClosing) { 2775 if (mClosing != isClosing) { 2776 mClosing = isClosing; 2777 mShadeExpansionStateManager.notifyPanelCollapsingChanged(isClosing); 2778 } 2779 mAmbientState.setIsClosing(isClosing); 2780 } 2781 updateDozingVisibilities(boolean animate)2782 private void updateDozingVisibilities(boolean animate) { 2783 mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate); 2784 if (!mDozing && animate) { 2785 mKeyguardStatusBarViewController.animateKeyguardStatusBarIn(); 2786 } 2787 } 2788 onScreenTurningOn()2789 public void onScreenTurningOn() { 2790 mKeyguardStatusViewController.dozeTimeTick(); 2791 } 2792 onMiddleClicked()2793 private void onMiddleClicked() { 2794 switch (mBarState) { 2795 case KEYGUARD: 2796 if (!mDozingOnDown) { 2797 mShadeLog.v("onMiddleClicked on Keyguard, mDozingOnDown: false"); 2798 // Try triggering face auth, this "might" run. Check 2799 // KeyguardUpdateMonitor#shouldListenForFace to see when face auth won't run. 2800 boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth( 2801 FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED); 2802 2803 if (didFaceAuthRun) { 2804 mUpdateMonitor.requestActiveUnlock( 2805 ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT, 2806 "lockScreenEmptySpaceTap"); 2807 } else { 2808 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT, 2809 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); 2810 mLockscreenGestureLogger 2811 .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT); 2812 startUnlockHintAnimation(); 2813 } 2814 } 2815 break; 2816 case StatusBarState.SHADE_LOCKED: 2817 if (!mQsController.getExpanded()) { 2818 mStatusBarStateController.setState(KEYGUARD); 2819 } 2820 break; 2821 } 2822 } 2823 setPanelAlpha(int alpha, boolean animate)2824 public void setPanelAlpha(int alpha, boolean animate) { 2825 if (mPanelAlpha != alpha) { 2826 mPanelAlpha = alpha; 2827 PropertyAnimator.setProperty(mView, mPanelAlphaAnimator, alpha, alpha == 255 2828 ? mPanelAlphaInPropertiesAnimator : mPanelAlphaOutPropertiesAnimator, 2829 animate); 2830 } 2831 } 2832 setPanelAlphaEndAction(Runnable r)2833 public void setPanelAlphaEndAction(Runnable r) { 2834 mPanelAlphaEndAction = r; 2835 } 2836 setHeadsUpAnimatingAway(boolean headsUpAnimatingAway)2837 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { 2838 mHeadsUpAnimatingAway = headsUpAnimatingAway; 2839 mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway); 2840 updateVisibility(); 2841 } 2842 2843 /** Set whether the bouncer is showing. */ setBouncerShowing(boolean bouncerShowing)2844 public void setBouncerShowing(boolean bouncerShowing) { 2845 mBouncerShowing = bouncerShowing; 2846 updateVisibility(); 2847 } 2848 shouldPanelBeVisible()2849 private boolean shouldPanelBeVisible() { 2850 boolean headsUpVisible = mHeadsUpAnimatingAway || mHeadsUpPinnedMode; 2851 return headsUpVisible || isExpanded() || mBouncerShowing; 2852 } 2853 setHeadsUpManager(HeadsUpManagerPhone headsUpManager)2854 public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) { 2855 mHeadsUpManager = headsUpManager; 2856 mHeadsUpManager.addListener(mOnHeadsUpChangedListener); 2857 mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, 2858 mNotificationStackScrollLayoutController.getHeadsUpCallback(), 2859 NotificationPanelViewController.this); 2860 } 2861 setTrackedHeadsUp(ExpandableNotificationRow pickedChild)2862 public void setTrackedHeadsUp(ExpandableNotificationRow pickedChild) { 2863 if (pickedChild != null) { 2864 updateTrackingHeadsUp(pickedChild); 2865 mExpandingFromHeadsUp = true; 2866 } 2867 // otherwise we update the state when the expansion is finished 2868 } 2869 onClosingFinished()2870 private void onClosingFinished() { 2871 mOpenCloseListener.onClosingFinished(); 2872 setClosingWithAlphaFadeout(false); 2873 mMediaHierarchyManager.closeGuts(); 2874 } 2875 setClosingWithAlphaFadeout(boolean closing)2876 private void setClosingWithAlphaFadeout(boolean closing) { 2877 mClosingWithAlphaFadeOut = closing; 2878 mNotificationStackScrollLayoutController.forceNoOverlappingRendering(closing); 2879 } 2880 updateExpandedHeight(float expandedHeight)2881 private void updateExpandedHeight(float expandedHeight) { 2882 if (mTracking) { 2883 mNotificationStackScrollLayoutController 2884 .setExpandingVelocity(getCurrentExpandVelocity()); 2885 } 2886 if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) { 2887 // The expandedHeight is always the full panel Height when bypassing 2888 expandedHeight = getMaxPanelHeight(); 2889 } 2890 mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight); 2891 updateKeyguardBottomAreaAlpha(); 2892 updateStatusBarIcons(); 2893 } 2894 updateStatusBarIcons()2895 private void updateStatusBarIcons() { 2896 boolean showIconsWhenExpanded = getExpandedHeight() < getOpeningHeight(); 2897 if (showIconsWhenExpanded && isOnKeyguard()) { 2898 showIconsWhenExpanded = false; 2899 } 2900 if (showIconsWhenExpanded != mShowIconsWhenExpanded) { 2901 mShowIconsWhenExpanded = showIconsWhenExpanded; 2902 mCommandQueue.recomputeDisableFlags(mDisplayId, false); 2903 } 2904 } 2905 2906 public int getBarState() { 2907 return mBarState; 2908 } 2909 2910 private boolean isOnKeyguard() { 2911 return mBarState == KEYGUARD; 2912 } 2913 2914 /** Called when a HUN is dragged up or down to indicate the starting height for shade motion. */ 2915 public void setHeadsUpDraggingStartingHeight(int startHeight) { 2916 mHeadsUpStartHeight = startHeight; 2917 float scrimMinFraction; 2918 if (mSplitShadeEnabled) { 2919 boolean highHun = mHeadsUpStartHeight * 2.5 2920 > 2921 (mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION) 2922 ? mSplitShadeFullTransitionDistance : mSplitShadeScrimTransitionDistance); 2923 // if HUN height is higher than 40% of predefined transition distance, it means HUN 2924 // is too high for regular transition. In that case we need to calculate transition 2925 // distance - here we take scrim transition distance as equal to shade transition 2926 // distance. It doesn't result in perfect motion - usually scrim transition distance 2927 // should be longer - but it's good enough for HUN case. 2928 float transitionDistance = 2929 highHun ? getMaxPanelTransitionDistance() : mSplitShadeFullTransitionDistance; 2930 scrimMinFraction = mHeadsUpStartHeight / transitionDistance; 2931 } else { 2932 int transitionDistance = getMaxPanelHeight(); 2933 scrimMinFraction = transitionDistance > 0f 2934 ? (float) mHeadsUpStartHeight / transitionDistance : 0f; 2935 } setPanelScrimMinFraction(scrimMinFraction)2936 setPanelScrimMinFraction(scrimMinFraction); 2937 } 2938 2939 /** 2940 * Sets the minimum fraction for the panel expansion offset. This may be non-zero in certain 2941 * cases, such as if there's a heads-up notification. 2942 */ setPanelScrimMinFraction(float minFraction)2943 private void setPanelScrimMinFraction(float minFraction) { 2944 mMinFraction = minFraction; 2945 mDepthController.setPanelPullDownMinFraction(mMinFraction); 2946 mScrimController.setPanelScrimMinFraction(mMinFraction); 2947 } 2948 clearNotificationEffects()2949 public void clearNotificationEffects() { 2950 mCentralSurfaces.clearNotificationEffects(); 2951 } 2952 isPanelVisibleBecauseOfHeadsUp()2953 private boolean isPanelVisibleBecauseOfHeadsUp() { 2954 return (mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway) 2955 && mBarState == StatusBarState.SHADE; 2956 } 2957 hideStatusBarIconsWhenExpanded()2958 public boolean hideStatusBarIconsWhenExpanded() { 2959 if (mIsLaunchAnimationRunning) { 2960 return mHideIconsDuringLaunchAnimation; 2961 } 2962 if (mHeadsUpAppearanceController != null 2963 && mHeadsUpAppearanceController.shouldBeVisible()) { 2964 return false; 2965 } 2966 return !mShowIconsWhenExpanded; 2967 } 2968 setTouchAndAnimationDisabled(boolean disabled)2969 public void setTouchAndAnimationDisabled(boolean disabled) { 2970 mTouchDisabled = disabled; 2971 if (mTouchDisabled) { 2972 cancelHeightAnimator(); 2973 if (mTracking) { 2974 onTrackingStopped(true /* expanded */); 2975 } 2976 notifyExpandingFinished(); 2977 } 2978 mNotificationStackScrollLayoutController.setAnimationsEnabled(!disabled); 2979 } 2980 2981 /** 2982 * Sets the dozing state. 2983 * 2984 * @param dozing {@code true} when dozing. 2985 * @param animate if transition should be animated. 2986 */ setDozing(boolean dozing, boolean animate)2987 public void setDozing(boolean dozing, boolean animate) { 2988 if (dozing == mDozing) return; 2989 mView.setDozing(dozing); 2990 mDozing = dozing; 2991 // TODO (b/) make listeners for this 2992 mNotificationStackScrollLayoutController.setDozing(mDozing, animate); 2993 mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate); 2994 mKeyguardStatusBarViewController.setDozing(mDozing); 2995 mQsController.setDozing(mDozing); 2996 2997 if (dozing) { 2998 mBottomAreaShadeAlphaAnimator.cancel(); 2999 } 3000 3001 if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) { 3002 updateDozingVisibilities(animate); 3003 } 3004 3005 final float dozeAmount = dozing ? 1 : 0; 3006 mStatusBarStateController.setAndInstrumentDozeAmount(mView, dozeAmount, animate); 3007 3008 updateKeyguardStatusViewAlignment(animate); 3009 } 3010 setPulsing(boolean pulsing)3011 public void setPulsing(boolean pulsing) { 3012 mPulsing = pulsing; 3013 final boolean 3014 animatePulse = 3015 !mDozeParameters.getDisplayNeedsBlanking() && mDozeParameters.getAlwaysOn(); 3016 if (animatePulse) { 3017 mAnimateNextPositionUpdate = true; 3018 } 3019 // Do not animate the clock when waking up from a pulse. 3020 // The height callback will take care of pushing the clock to the right position. 3021 if (!mPulsing && !mDozing) { 3022 mAnimateNextPositionUpdate = false; 3023 } 3024 mNotificationStackScrollLayoutController.setPulsing(pulsing, animatePulse); 3025 3026 updateKeyguardStatusViewAlignment(/* animate= */ true); 3027 } 3028 setAmbientIndicationTop(int ambientIndicationTop, boolean ambientTextVisible)3029 public void setAmbientIndicationTop(int ambientIndicationTop, boolean ambientTextVisible) { 3030 int ambientIndicationBottomPadding = 0; 3031 if (ambientTextVisible) { 3032 int stackBottom = mNotificationStackScrollLayoutController.getBottom(); 3033 ambientIndicationBottomPadding = stackBottom - ambientIndicationTop; 3034 } 3035 if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) { 3036 mAmbientIndicationBottomPadding = ambientIndicationBottomPadding; 3037 updateMaxDisplayedNotifications(true); 3038 } 3039 } 3040 dozeTimeTick()3041 public void dozeTimeTick() { 3042 mLockIconViewController.dozeTimeTick(); 3043 mKeyguardStatusViewController.dozeTimeTick(); 3044 if (mInterpolatedDarkAmount > 0) { 3045 positionClockAndNotifications(); 3046 } 3047 } 3048 setStatusAccessibilityImportance(int mode)3049 public void setStatusAccessibilityImportance(int mode) { 3050 mKeyguardStatusViewController.setStatusAccessibilityImportance(mode); 3051 } 3052 3053 //TODO(b/254875405): this should be removed. getKeyguardBottomAreaView()3054 public KeyguardBottomAreaView getKeyguardBottomAreaView() { 3055 return mKeyguardBottomArea; 3056 } 3057 applyLaunchAnimationProgress(float linearProgress)3058 public void applyLaunchAnimationProgress(float linearProgress) { 3059 boolean hideIcons = LaunchAnimator.getProgress(ActivityLaunchAnimator.TIMINGS, 3060 linearProgress, ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f; 3061 if (hideIcons != mHideIconsDuringLaunchAnimation) { 3062 mHideIconsDuringLaunchAnimation = hideIcons; 3063 if (!hideIcons) { 3064 mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */); 3065 } 3066 } 3067 } 3068 addTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener)3069 public void addTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) { 3070 mTrackingHeadsUpListeners.add(listener); 3071 } 3072 removeTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener)3073 public void removeTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) { 3074 mTrackingHeadsUpListeners.remove(listener); 3075 } 3076 setHeadsUpAppearanceController( HeadsUpAppearanceController headsUpAppearanceController)3077 public void setHeadsUpAppearanceController( 3078 HeadsUpAppearanceController headsUpAppearanceController) { 3079 mHeadsUpAppearanceController = headsUpAppearanceController; 3080 } 3081 3082 /** Called before animating Keyguard dismissal, i.e. the animation dismissing the bouncer. */ startBouncerPreHideAnimation()3083 public void startBouncerPreHideAnimation() { 3084 if (mKeyguardQsUserSwitchController != null) { 3085 mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility( 3086 mBarState, 3087 true /* keyguardFadingAway */, 3088 false /* goingToFullShade */, 3089 mBarState); 3090 } 3091 if (mKeyguardUserSwitcherController != null) { 3092 mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( 3093 mBarState, 3094 true /* keyguardFadingAway */, 3095 false /* goingToFullShade */, 3096 mBarState); 3097 } 3098 } 3099 3100 /** Updates the views to the initial state for the fold to AOD animation. */ prepareFoldToAodAnimation()3101 public void prepareFoldToAodAnimation() { 3102 // Force show AOD UI even if we are not locked 3103 showAodUi(); 3104 3105 // Move the content of the AOD all the way to the left 3106 // so we can animate to the initial position 3107 final int translationAmount = mView.getResources().getDimensionPixelSize( 3108 R.dimen.below_clock_padding_start); 3109 mView.setTranslationX(-translationAmount); 3110 mView.setAlpha(0); 3111 } 3112 3113 /** 3114 * Starts fold to AOD animation. 3115 * 3116 * @param startAction invoked when the animation starts. 3117 * @param endAction invoked when the animation finishes, also if it was cancelled. 3118 * @param cancelAction invoked when the animation is cancelled, before endAction. 3119 */ startFoldToAodAnimation(Runnable startAction, Runnable endAction, Runnable cancelAction)3120 public void startFoldToAodAnimation(Runnable startAction, Runnable endAction, 3121 Runnable cancelAction) { 3122 final ViewPropertyAnimator viewAnimator = mView.animate(); 3123 viewAnimator.cancel(); 3124 viewAnimator 3125 .translationX(0) 3126 .alpha(1f) 3127 .setDuration(ANIMATION_DURATION_FOLD_TO_AOD) 3128 .setInterpolator(EMPHASIZED_DECELERATE) 3129 .setListener(new AnimatorListenerAdapter() { 3130 @Override 3131 public void onAnimationStart(Animator animation) { 3132 startAction.run(); 3133 } 3134 3135 @Override 3136 public void onAnimationCancel(Animator animation) { 3137 cancelAction.run(); 3138 } 3139 3140 @Override 3141 public void onAnimationEnd(Animator animation) { 3142 endAction.run(); 3143 3144 viewAnimator.setListener(null); 3145 viewAnimator.setUpdateListener(null); 3146 } 3147 }) 3148 .setUpdateListener(anim -> 3149 mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction())) 3150 .start(); 3151 } 3152 3153 /** Cancels fold to AOD transition and resets view state. */ cancelFoldToAodAnimation()3154 public void cancelFoldToAodAnimation() { 3155 cancelAnimation(); 3156 resetAlpha(); 3157 resetTranslation(); 3158 } 3159 setImportantForAccessibility(int mode)3160 public void setImportantForAccessibility(int mode) { 3161 mView.setImportantForAccessibility(mode); 3162 } 3163 3164 /** 3165 * Do not let the user drag the shade up and down for the current touch session. 3166 * This is necessary to avoid shade expansion while/after the bouncer is dismissed. 3167 */ blockExpansionForCurrentTouch()3168 public void blockExpansionForCurrentTouch() { 3169 mBlockingExpansionForCurrentTouch = mTracking; 3170 } 3171 3172 @Override dump(PrintWriter pw, String[] args)3173 public void dump(PrintWriter pw, String[] args) { 3174 pw.println(TAG + ":"); 3175 IndentingPrintWriter ipw = asIndenting(pw); 3176 ipw.increaseIndent(); 3177 3178 ipw.print("mDownTime="); ipw.println(mDownTime); 3179 ipw.print("mTouchSlopExceededBeforeDown="); ipw.println(mTouchSlopExceededBeforeDown); 3180 ipw.print("mIsLaunchAnimationRunning="); ipw.println(mIsLaunchAnimationRunning); 3181 ipw.print("mOverExpansion="); ipw.println(mOverExpansion); 3182 ipw.print("mExpandedHeight="); ipw.println(mExpandedHeight); 3183 ipw.print("mTracking="); ipw.println(mTracking); 3184 ipw.print("mHintAnimationRunning="); ipw.println(mHintAnimationRunning); 3185 ipw.print("mExpanding="); ipw.println(mExpanding); 3186 ipw.print("mSplitShadeEnabled="); ipw.println(mSplitShadeEnabled); 3187 ipw.print("mKeyguardNotificationBottomPadding="); 3188 ipw.println(mKeyguardNotificationBottomPadding); 3189 ipw.print("mKeyguardNotificationTopPadding="); ipw.println(mKeyguardNotificationTopPadding); 3190 ipw.print("mMaxAllowedKeyguardNotifications="); 3191 ipw.println(mMaxAllowedKeyguardNotifications); 3192 ipw.print("mAnimateNextPositionUpdate="); ipw.println(mAnimateNextPositionUpdate); 3193 ipw.print("mPanelExpanded="); ipw.println(mPanelExpanded); 3194 ipw.print("mKeyguardQsUserSwitchEnabled="); ipw.println(mKeyguardQsUserSwitchEnabled); 3195 ipw.print("mKeyguardUserSwitcherEnabled="); ipw.println(mKeyguardUserSwitcherEnabled); 3196 ipw.print("mDozing="); ipw.println(mDozing); 3197 ipw.print("mDozingOnDown="); ipw.println(mDozingOnDown); 3198 ipw.print("mBouncerShowing="); ipw.println(mBouncerShowing); 3199 ipw.print("mBarState="); ipw.println(mBarState); 3200 ipw.print("mStatusBarMinHeight="); ipw.println(mStatusBarMinHeight); 3201 ipw.print("mStatusBarHeaderHeightKeyguard="); ipw.println(mStatusBarHeaderHeightKeyguard); 3202 ipw.print("mOverStretchAmount="); ipw.println(mOverStretchAmount); 3203 ipw.print("mDownX="); ipw.println(mDownX); 3204 ipw.print("mDownY="); ipw.println(mDownY); 3205 ipw.print("mDisplayTopInset="); ipw.println(mDisplayTopInset); 3206 ipw.print("mDisplayRightInset="); ipw.println(mDisplayRightInset); 3207 ipw.print("mDisplayLeftInset="); ipw.println(mDisplayLeftInset); 3208 ipw.print("mIsExpanding="); ipw.println(mIsExpanding); 3209 ipw.print("mHeaderDebugInfo="); ipw.println(mHeaderDebugInfo); 3210 ipw.print("mHeadsUpStartHeight="); ipw.println(mHeadsUpStartHeight); 3211 ipw.print("mListenForHeadsUp="); ipw.println(mListenForHeadsUp); 3212 ipw.print("mNavigationBarBottomHeight="); ipw.println(mNavigationBarBottomHeight); 3213 ipw.print("mExpandingFromHeadsUp="); ipw.println(mExpandingFromHeadsUp); 3214 ipw.print("mCollapsedOnDown="); ipw.println(mCollapsedOnDown); 3215 ipw.print("mClosingWithAlphaFadeOut="); ipw.println(mClosingWithAlphaFadeOut); 3216 ipw.print("mHeadsUpAnimatingAway="); ipw.println(mHeadsUpAnimatingAway); 3217 ipw.print("mShowIconsWhenExpanded="); ipw.println(mShowIconsWhenExpanded); 3218 ipw.print("mIndicationBottomPadding="); ipw.println(mIndicationBottomPadding); 3219 ipw.print("mAmbientIndicationBottomPadding="); ipw.println(mAmbientIndicationBottomPadding); 3220 ipw.print("mIsFullWidth="); ipw.println(mIsFullWidth); 3221 ipw.print("mBlockingExpansionForCurrentTouch="); 3222 ipw.println(mBlockingExpansionForCurrentTouch); 3223 ipw.print("mExpectingSynthesizedDown="); ipw.println(mExpectingSynthesizedDown); 3224 ipw.print("mLastEventSynthesizedDown="); ipw.println(mLastEventSynthesizedDown); 3225 ipw.print("mInterpolatedDarkAmount="); ipw.println(mInterpolatedDarkAmount); 3226 ipw.print("mLinearDarkAmount="); ipw.println(mLinearDarkAmount); 3227 ipw.print("mPulsing="); ipw.println(mPulsing); 3228 ipw.print("mHideIconsDuringLaunchAnimation="); ipw.println(mHideIconsDuringLaunchAnimation); 3229 ipw.print("mStackScrollerMeasuringPass="); ipw.println(mStackScrollerMeasuringPass); 3230 ipw.print("mPanelAlpha="); ipw.println(mPanelAlpha); 3231 ipw.print("mBottomAreaShadeAlpha="); ipw.println(mBottomAreaShadeAlpha); 3232 ipw.print("mHeadsUpInset="); ipw.println(mHeadsUpInset); 3233 ipw.print("mHeadsUpPinnedMode="); ipw.println(mHeadsUpPinnedMode); 3234 ipw.print("mAllowExpandForSmallExpansion="); ipw.println(mAllowExpandForSmallExpansion); 3235 ipw.print("mMaxOverscrollAmountForPulse="); ipw.println(mMaxOverscrollAmountForPulse); 3236 ipw.print("mIsPanelCollapseOnQQS="); ipw.println(mIsPanelCollapseOnQQS); 3237 ipw.print("mKeyguardOnlyContentAlpha="); ipw.println(mKeyguardOnlyContentAlpha); 3238 ipw.print("mKeyguardOnlyTransitionTranslationY="); 3239 ipw.println(mKeyguardOnlyTransitionTranslationY); 3240 ipw.print("mUdfpsMaxYBurnInOffset="); ipw.println(mUdfpsMaxYBurnInOffset); 3241 ipw.print("mIsGestureNavigation="); ipw.println(mIsGestureNavigation); 3242 ipw.print("mOldLayoutDirection="); ipw.println(mOldLayoutDirection); 3243 ipw.print("mMinFraction="); ipw.println(mMinFraction); 3244 ipw.print("mStatusViewCentered="); ipw.println(mStatusViewCentered); 3245 ipw.print("mSplitShadeFullTransitionDistance="); 3246 ipw.println(mSplitShadeFullTransitionDistance); 3247 ipw.print("mSplitShadeScrimTransitionDistance="); 3248 ipw.println(mSplitShadeScrimTransitionDistance); 3249 ipw.print("mMinExpandHeight="); ipw.println(mMinExpandHeight); 3250 ipw.print("mPanelUpdateWhenAnimatorEnds="); ipw.println(mPanelUpdateWhenAnimatorEnds); 3251 ipw.print("mHasVibratedOnOpen="); ipw.println(mHasVibratedOnOpen); 3252 ipw.print("mFixedDuration="); ipw.println(mFixedDuration); 3253 ipw.print("mPanelFlingOvershootAmount="); ipw.println(mPanelFlingOvershootAmount); 3254 ipw.print("mLastGesturedOverExpansion="); ipw.println(mLastGesturedOverExpansion); 3255 ipw.print("mIsSpringBackAnimation="); ipw.println(mIsSpringBackAnimation); 3256 ipw.print("mSplitShadeEnabled="); ipw.println(mSplitShadeEnabled); 3257 ipw.print("mHintDistance="); ipw.println(mHintDistance); 3258 ipw.print("mInitialOffsetOnTouch="); ipw.println(mInitialOffsetOnTouch); 3259 ipw.print("mCollapsedAndHeadsUpOnDown="); ipw.println(mCollapsedAndHeadsUpOnDown); 3260 ipw.print("mExpandedFraction="); ipw.println(mExpandedFraction); 3261 ipw.print("mExpansionDragDownAmountPx="); ipw.println(mExpansionDragDownAmountPx); 3262 ipw.print("mPanelClosedOnDown="); ipw.println(mPanelClosedOnDown); 3263 ipw.print("mHasLayoutedSinceDown="); ipw.println(mHasLayoutedSinceDown); 3264 ipw.print("mUpdateFlingVelocity="); ipw.println(mUpdateFlingVelocity); 3265 ipw.print("mUpdateFlingOnLayout="); ipw.println(mUpdateFlingOnLayout); 3266 ipw.print("mClosing="); ipw.println(mClosing); 3267 ipw.print("mTouchSlopExceeded="); ipw.println(mTouchSlopExceeded); 3268 ipw.print("mTrackingPointer="); ipw.println(mTrackingPointer); 3269 ipw.print("mTouchSlop="); ipw.println(mTouchSlop); 3270 ipw.print("mSlopMultiplier="); ipw.println(mSlopMultiplier); 3271 ipw.print("mTouchAboveFalsingThreshold="); ipw.println(mTouchAboveFalsingThreshold); 3272 ipw.print("mTouchStartedInEmptyArea="); ipw.println(mTouchStartedInEmptyArea); 3273 ipw.print("mMotionAborted="); ipw.println(mMotionAborted); 3274 ipw.print("mUpwardsWhenThresholdReached="); ipw.println(mUpwardsWhenThresholdReached); 3275 ipw.print("mAnimatingOnDown="); ipw.println(mAnimatingOnDown); 3276 ipw.print("mHandlingPointerUp="); ipw.println(mHandlingPointerUp); 3277 ipw.print("mInstantExpanding="); ipw.println(mInstantExpanding); 3278 ipw.print("mAnimateAfterExpanding="); ipw.println(mAnimateAfterExpanding); 3279 ipw.print("mIsFlinging="); ipw.println(mIsFlinging); 3280 ipw.print("mViewName="); ipw.println(mViewName); 3281 ipw.print("mInitialExpandY="); ipw.println(mInitialExpandY); 3282 ipw.print("mInitialExpandX="); ipw.println(mInitialExpandX); 3283 ipw.print("mTouchDisabled="); ipw.println(mTouchDisabled); 3284 ipw.print("mInitialTouchFromKeyguard="); ipw.println(mInitialTouchFromKeyguard); 3285 ipw.print("mNextCollapseSpeedUpFactor="); ipw.println(mNextCollapseSpeedUpFactor); 3286 ipw.print("mGestureWaitForTouchSlop="); ipw.println(mGestureWaitForTouchSlop); 3287 ipw.print("mIgnoreXTouchSlop="); ipw.println(mIgnoreXTouchSlop); 3288 ipw.print("mExpandLatencyTracking="); ipw.println(mExpandLatencyTracking); 3289 ipw.print("mExpandLatencyTracking="); ipw.println(mExpandLatencyTracking); 3290 ipw.println("gestureExclusionRect:" + calculateGestureExclusionRect()); 3291 new DumpsysTableLogger( 3292 TAG, 3293 NPVCDownEventState.TABLE_HEADERS, 3294 mLastDownEvents.toList() 3295 ).printTableData(ipw); 3296 } 3297 3298 createRemoteInputDelegate()3299 public RemoteInputController.Delegate createRemoteInputDelegate() { 3300 return mNotificationStackScrollLayoutController.createDelegate(); 3301 } 3302 hasPulsingNotifications()3303 public boolean hasPulsingNotifications() { 3304 return mNotificationListContainer.hasPulsingNotifications(); 3305 } 3306 getActivatedChild()3307 public ActivatableNotificationView getActivatedChild() { 3308 return mNotificationStackScrollLayoutController.getActivatedChild(); 3309 } 3310 setActivatedChild(ActivatableNotificationView o)3311 public void setActivatedChild(ActivatableNotificationView o) { 3312 mNotificationStackScrollLayoutController.setActivatedChild(o); 3313 } 3314 runAfterAnimationFinished(Runnable r)3315 public void runAfterAnimationFinished(Runnable r) { 3316 mNotificationStackScrollLayoutController.runAfterAnimationFinished(r); 3317 } 3318 3319 /** 3320 * Initialize objects instead of injecting to avoid circular dependencies. 3321 * 3322 * @param hideExpandedRunnable a runnable to run when we need to hide the expanded panel. 3323 */ initDependencies( CentralSurfaces centralSurfaces, GestureRecorder recorder, Runnable hideExpandedRunnable, NotificationShelfController notificationShelfController)3324 public void initDependencies( 3325 CentralSurfaces centralSurfaces, 3326 GestureRecorder recorder, 3327 Runnable hideExpandedRunnable, 3328 NotificationShelfController notificationShelfController) { 3329 // TODO(b/254859580): this can be injected. 3330 mCentralSurfaces = centralSurfaces; 3331 3332 mGestureRecorder = recorder; 3333 mHideExpandedRunnable = hideExpandedRunnable; 3334 mNotificationStackScrollLayoutController.setShelfController(notificationShelfController); 3335 mNotificationShelfController = notificationShelfController; 3336 mLockscreenShadeTransitionController.bindController(notificationShelfController); 3337 updateMaxDisplayedNotifications(true); 3338 } 3339 resetTranslation()3340 public void resetTranslation() { 3341 mView.setTranslationX(0f); 3342 } 3343 resetAlpha()3344 public void resetAlpha() { 3345 mView.setAlpha(1f); 3346 } 3347 fadeOut(long startDelayMs, long durationMs, Runnable endAction)3348 public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) { 3349 mView.animate().cancel(); 3350 return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration( 3351 durationMs).setInterpolator(Interpolators.ALPHA_OUT).withLayer().withEndAction( 3352 endAction); 3353 } 3354 resetViewGroupFade()3355 public void resetViewGroupFade() { 3356 ViewGroupFadeHelper.reset(mView); 3357 } 3358 addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener)3359 void addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) { 3360 mView.getViewTreeObserver().addOnGlobalLayoutListener(listener); 3361 } 3362 removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener)3363 void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) { 3364 mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener); 3365 } 3366 setHeaderDebugInfo(String text)3367 public void setHeaderDebugInfo(String text) { 3368 if (DEBUG_DRAWABLE) mHeaderDebugInfo = text; 3369 } 3370 getHeaderDebugInfo()3371 public String getHeaderDebugInfo() { 3372 return mHeaderDebugInfo; 3373 } 3374 onThemeChanged()3375 public void onThemeChanged() { 3376 mConfigurationListener.onThemeChanged(); 3377 } 3378 3379 @VisibleForTesting getTouchHandler()3380 TouchHandler getTouchHandler() { 3381 return mTouchHandler; 3382 } 3383 getNotificationStackScrollLayoutController()3384 public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() { 3385 return mNotificationStackScrollLayoutController; 3386 } 3387 disable(int state1, int state2, boolean animated)3388 public void disable(int state1, int state2, boolean animated) { 3389 mShadeHeaderController.disable(state1, state2, animated); 3390 } 3391 3392 /** 3393 * Close the keyguard user switcher if it is open and capable of closing. 3394 * 3395 * Has no effect if user switcher isn't supported, if the user switcher is already closed, or 3396 * if the user switcher uses "simple" mode. The simple user switcher cannot be closed. 3397 * 3398 * @return true if the keyguard user switcher was open, and is now closed 3399 */ closeUserSwitcherIfOpen()3400 public boolean closeUserSwitcherIfOpen() { 3401 if (mKeyguardUserSwitcherController != null) { 3402 return mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple( 3403 true /* animate */); 3404 } 3405 return false; 3406 } 3407 updateUserSwitcherFlags()3408 private void updateUserSwitcherFlags() { 3409 mKeyguardUserSwitcherEnabled = mResources.getBoolean( 3410 com.android.internal.R.bool.config_keyguardUserSwitcher); 3411 mKeyguardQsUserSwitchEnabled = 3412 mKeyguardUserSwitcherEnabled 3413 && mFeatureFlags.isEnabled(Flags.QS_USER_DETAIL_SHORTCUT); 3414 } 3415 registerSettingsChangeListener()3416 private void registerSettingsChangeListener() { 3417 mContentResolver.registerContentObserver( 3418 Settings.Global.getUriFor(Settings.Global.USER_SWITCHER_ENABLED), 3419 /* notifyForDescendants */ false, 3420 mSettingsChangeObserver 3421 ); 3422 } 3423 3424 /** Updates notification panel-specific flags on {@link SysUiState}. */ updateSystemUiStateFlags()3425 public void updateSystemUiStateFlags() { 3426 if (SysUiState.DEBUG) { 3427 Log.d(TAG, "Updating panel sysui state flags: fullyExpanded=" 3428 + isFullyExpanded() + " inQs=" + mQsController.getExpanded()); 3429 } 3430 mSysUiState 3431 .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, getExpandedFraction() > 0) 3432 .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED, 3433 isFullyExpanded() && !mQsController.getExpanded()) 3434 .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED, 3435 isFullyExpanded() && mQsController.getExpanded()).commitUpdate(mDisplayId); 3436 } 3437 debugLog(String fmt, Object... args)3438 private void debugLog(String fmt, Object... args) { 3439 if (DEBUG_LOGCAT) { 3440 Log.d(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); 3441 } 3442 } 3443 3444 @VisibleForTesting notifyExpandingStarted()3445 void notifyExpandingStarted() { 3446 if (!mExpanding) { 3447 mExpanding = true; 3448 mIsExpanding = true; 3449 mQsController.onExpandingStarted(mQsController.getFullyExpanded()); 3450 } 3451 } 3452 notifyExpandingFinished()3453 void notifyExpandingFinished() { 3454 endClosing(); 3455 if (mExpanding) { 3456 mExpanding = false; 3457 onExpandingFinished(); 3458 } 3459 } 3460 getTouchSlop(MotionEvent event)3461 float getTouchSlop(MotionEvent event) { 3462 // Adjust the touch slop if another gesture may be being performed. 3463 return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE 3464 ? mTouchSlop * mSlopMultiplier 3465 : mTouchSlop; 3466 } 3467 addMovement(MotionEvent event)3468 private void addMovement(MotionEvent event) { 3469 // Add movement to velocity tracker using raw screen X and Y coordinates instead 3470 // of window coordinates because the window frame may be moving at the same time. 3471 float deltaX = event.getRawX() - event.getX(); 3472 float deltaY = event.getRawY() - event.getY(); 3473 event.offsetLocation(deltaX, deltaY); 3474 mVelocityTracker.addMovement(event); 3475 event.offsetLocation(-deltaX, -deltaY); 3476 } 3477 3478 /** If the latency tracker is enabled, begins tracking expand latency. */ startExpandLatencyTracking()3479 public void startExpandLatencyTracking() { 3480 if (mLatencyTracker.isEnabled()) { 3481 mLatencyTracker.onActionStart(LatencyTracker.ACTION_EXPAND_PANEL); 3482 mExpandLatencyTracking = true; 3483 } 3484 } 3485 startOpening(MotionEvent event)3486 private void startOpening(MotionEvent event) { 3487 updatePanelExpansionAndVisibility(); 3488 //TODO: keyguard opens QS a different way; log that too? 3489 3490 // Log the position of the swipe that opened the panel 3491 float width = mCentralSurfaces.getDisplayWidth(); 3492 float height = mCentralSurfaces.getDisplayHeight(); 3493 int rot = mCentralSurfaces.getRotation(); 3494 3495 mLockscreenGestureLogger.writeAtFractionalPosition(MetricsEvent.ACTION_PANEL_VIEW_EXPAND, 3496 (int) (event.getX() / width * 100), (int) (event.getY() / height * 100), rot); 3497 mLockscreenGestureLogger 3498 .log(LockscreenUiEvent.LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND); 3499 } 3500 3501 /** 3502 * Maybe vibrate as panel is opened. 3503 * 3504 * @param openingWithTouch Whether the panel is being opened with touch. If the panel is 3505 * instead being opened programmatically (such as by the open panel 3506 * gesture), we always play haptic. 3507 */ maybeVibrateOnOpening(boolean openingWithTouch)3508 private void maybeVibrateOnOpening(boolean openingWithTouch) { 3509 if (mVibrateOnOpening) { 3510 if (!openingWithTouch || !mHasVibratedOnOpen) { 3511 mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK); 3512 mHasVibratedOnOpen = true; 3513 mShadeLog.v("Vibrating on opening, mHasVibratedOnOpen=true"); 3514 } 3515 } 3516 } 3517 3518 /** 3519 * @return whether the swiping direction is upwards and above a 45 degree angle compared to the 3520 * horizontal direction 3521 */ isDirectionUpwards(float x, float y)3522 private boolean isDirectionUpwards(float x, float y) { 3523 float xDiff = x - mInitialExpandX; 3524 float yDiff = y - mInitialExpandY; 3525 if (yDiff >= 0) { 3526 return false; 3527 } 3528 return Math.abs(yDiff) >= Math.abs(xDiff); 3529 } 3530 3531 /** Called when a MotionEvent is about to trigger Shade expansion. */ startExpandMotion(float newX, float newY, boolean startTracking, float expandedHeight)3532 public void startExpandMotion(float newX, float newY, boolean startTracking, 3533 float expandedHeight) { 3534 if (!mHandlingPointerUp && !mStatusBarStateController.isDozing()) { 3535 mQsController.beginJankMonitoring(isFullyCollapsed()); 3536 } 3537 mInitialOffsetOnTouch = expandedHeight; 3538 if (!mTracking || isFullyCollapsed()) { 3539 mInitialExpandY = newY; 3540 mInitialExpandX = newX; 3541 } else { 3542 mShadeLog.d("not setting mInitialExpandY in startExpandMotion"); 3543 } 3544 mInitialTouchFromKeyguard = mKeyguardStateController.isShowing(); 3545 if (startTracking) { 3546 mTouchSlopExceeded = true; 3547 mShadeHeightLogger.logFunctionCall("startExpandMotion"); 3548 setExpandedHeight(mInitialOffsetOnTouch); 3549 onTrackingStarted(); 3550 } 3551 } 3552 endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel)3553 private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) { 3554 mTrackingPointer = -1; 3555 mAmbientState.setSwipingUp(false); 3556 if ((mTracking && mTouchSlopExceeded) || Math.abs(x - mInitialExpandX) > mTouchSlop 3557 || Math.abs(y - mInitialExpandY) > mTouchSlop 3558 || (!isFullyExpanded() && !isFullyCollapsed()) 3559 || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) { 3560 mVelocityTracker.computeCurrentVelocity(1000); 3561 float vel = mVelocityTracker.getYVelocity(); 3562 float vectorVel = (float) Math.hypot( 3563 mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity()); 3564 3565 final boolean onKeyguard = mKeyguardStateController.isShowing(); 3566 final boolean expand; 3567 if (mKeyguardStateController.isKeyguardFadingAway() 3568 || (mInitialTouchFromKeyguard && !onKeyguard)) { 3569 // Don't expand for any touches that started from the keyguard and ended after the 3570 // keyguard is gone. 3571 expand = false; 3572 } else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) { 3573 if (onKeyguard) { 3574 expand = true; 3575 } else if (mCentralSurfaces.isBouncerShowingOverDream()) { 3576 expand = false; 3577 } else { 3578 // If we get a cancel, put the shade back to the state it was in when the 3579 // gesture started 3580 expand = !mPanelClosedOnDown; 3581 } 3582 } else { 3583 expand = flingExpands(vel, vectorVel, x, y); 3584 } 3585 3586 mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold, 3587 mCentralSurfaces.isWakeUpComingFromTouch()); 3588 // Log collapse gesture if on lock screen. 3589 if (!expand && onKeyguard) { 3590 float displayDensity = mCentralSurfaces.getDisplayDensity(); 3591 int heightDp = (int) Math.abs((y - mInitialExpandY) / displayDensity); 3592 int velocityDp = (int) Math.abs(vel / displayDensity); 3593 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp); 3594 mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK); 3595 } 3596 @Classifier.InteractionType int interactionType = vel == 0 ? GENERIC 3597 : y - mInitialExpandY > 0 ? QUICK_SETTINGS 3598 : (mKeyguardStateController.canDismissLockScreen() 3599 ? UNLOCK : BOUNCER_UNLOCK); 3600 3601 // don't fling while in keyguard to avoid jump in shade expand animation; 3602 // touch has been intercepted already so flinging here is redundant 3603 if (mBarState == KEYGUARD && mExpandedFraction >= 1.0) { 3604 mShadeLog.d("NPVC endMotionEvent - skipping fling on keyguard"); 3605 } else { 3606 fling(vel, expand, isFalseTouch(x, y, interactionType)); 3607 } 3608 onTrackingStopped(expand); 3609 mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown; 3610 if (mUpdateFlingOnLayout) { 3611 mUpdateFlingVelocity = vel; 3612 } 3613 } else if (!mCentralSurfaces.isBouncerShowing() 3614 && !mAlternateBouncerInteractor.isVisibleState() 3615 && !mKeyguardStateController.isKeyguardGoingAway()) { 3616 onEmptySpaceClick(); 3617 onTrackingStopped(true); 3618 } 3619 mVelocityTracker.clear(); 3620 } 3621 getCurrentExpandVelocity()3622 private float getCurrentExpandVelocity() { 3623 mVelocityTracker.computeCurrentVelocity(1000); 3624 return mVelocityTracker.getYVelocity(); 3625 } 3626 endClosing()3627 private void endClosing() { 3628 if (mClosing) { 3629 setClosing(false); 3630 onClosingFinished(); 3631 } 3632 } 3633 3634 /** 3635 * @param x the final x-coordinate when the finger was lifted 3636 * @param y the final y-coordinate when the finger was lifted 3637 * @return whether this motion should be regarded as a false touch 3638 */ isFalseTouch(float x, float y, @Classifier.InteractionType int interactionType)3639 private boolean isFalseTouch(float x, float y, 3640 @Classifier.InteractionType int interactionType) { 3641 if (mFalsingManager.isClassifierEnabled()) { 3642 return mFalsingManager.isFalseTouch(interactionType); 3643 } 3644 if (!mTouchAboveFalsingThreshold) { 3645 return true; 3646 } 3647 if (mUpwardsWhenThresholdReached) { 3648 return false; 3649 } 3650 return !isDirectionUpwards(x, y); 3651 } 3652 fling(float vel, boolean expand, boolean expandBecauseOfFalsing)3653 private void fling(float vel, boolean expand, boolean expandBecauseOfFalsing) { 3654 fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, expandBecauseOfFalsing); 3655 } 3656 fling(float vel, boolean expand, float collapseSpeedUpFactor, boolean expandBecauseOfFalsing)3657 private void fling(float vel, boolean expand, float collapseSpeedUpFactor, 3658 boolean expandBecauseOfFalsing) { 3659 float target = expand ? getMaxPanelTransitionDistance() : 0; 3660 if (!expand) { 3661 setClosing(true); 3662 } 3663 flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing); 3664 } 3665 springBack()3666 private void springBack() { 3667 if (mOverExpansion == 0) { 3668 onFlingEnd(false /* cancelled */); 3669 return; 3670 } 3671 mIsSpringBackAnimation = true; 3672 ValueAnimator animator = ValueAnimator.ofFloat(mOverExpansion, 0); 3673 animator.addUpdateListener( 3674 animation -> setOverExpansionInternal((float) animation.getAnimatedValue(), 3675 false /* isFromGesture */)); 3676 animator.setDuration(SHADE_OPEN_SPRING_BACK_DURATION); 3677 animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 3678 animator.addListener(new AnimatorListenerAdapter() { 3679 private boolean mCancelled; 3680 3681 @Override 3682 public void onAnimationCancel(Animator animation) { 3683 mCancelled = true; 3684 } 3685 3686 @Override 3687 public void onAnimationEnd(Animator animation) { 3688 mIsSpringBackAnimation = false; 3689 onFlingEnd(mCancelled); 3690 } 3691 }); 3692 setAnimator(animator); 3693 animator.start(); 3694 } 3695 3696 @VisibleForTesting setExpandedHeight(float height)3697 void setExpandedHeight(float height) { 3698 debugLog("setExpandedHeight(%.1f)", height); 3699 mShadeHeightLogger.logFunctionCall("setExpandedHeight"); 3700 setExpandedHeightInternal(height); 3701 } 3702 3703 /** Try to set expanded height to max. */ updateExpandedHeightToMaxHeight()3704 void updateExpandedHeightToMaxHeight() { 3705 float currentMaxPanelHeight = getMaxPanelHeight(); 3706 3707 if (isFullyCollapsed()) { 3708 return; 3709 } 3710 3711 if (currentMaxPanelHeight == mExpandedHeight) { 3712 return; 3713 } 3714 3715 if (mTracking && !(mBlockingExpansionForCurrentTouch 3716 || mQsController.isTrackingBlocked())) { 3717 return; 3718 } 3719 3720 if (mHeightAnimator != null && !mIsSpringBackAnimation) { 3721 mPanelUpdateWhenAnimatorEnds = true; 3722 return; 3723 } 3724 3725 mShadeHeightLogger.logFunctionCall("updateExpandedHeightToMaxHeight"); 3726 setExpandedHeight(currentMaxPanelHeight); 3727 } 3728 setExpandedHeightInternal(float h)3729 private void setExpandedHeightInternal(float h) { 3730 mShadeHeightLogger.logSetExpandedHeightInternal(h, mSystemClock.currentTimeMillis()); 3731 3732 if (isNaN(h)) { 3733 Log.wtf(TAG, "ExpandedHeight set to NaN"); 3734 } 3735 mNotificationShadeWindowController.batchApplyWindowLayoutParams(() -> { 3736 if (mExpandLatencyTracking && h != 0f) { 3737 DejankUtils.postAfterTraversal( 3738 () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL)); 3739 mExpandLatencyTracking = false; 3740 } 3741 float maxPanelHeight = getMaxPanelTransitionDistance(); 3742 if (mHeightAnimator == null) { 3743 // Split shade has its own overscroll logic 3744 if (mTracking) { 3745 float overExpansionPixels = Math.max(0, h - maxPanelHeight); 3746 setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */); 3747 } 3748 } 3749 mExpandedHeight = Math.min(h, maxPanelHeight); 3750 // If we are closing the panel and we are almost there due to a slow decelerating 3751 // interpolator, abort the animation. 3752 if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) { 3753 mExpandedHeight = 0f; 3754 if (mHeightAnimator != null) { 3755 mHeightAnimator.end(); 3756 } 3757 } 3758 mExpandedFraction = Math.min(1f, 3759 maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight); 3760 mQsController.setShadeExpansion(mExpandedHeight, mExpandedFraction); 3761 mExpansionDragDownAmountPx = h; 3762 mAmbientState.setExpansionFraction(mExpandedFraction); 3763 onHeightUpdated(mExpandedHeight); 3764 updatePanelExpansionAndVisibility(); 3765 }); 3766 } 3767 3768 /** 3769 * Set the current overexpansion 3770 * 3771 * @param overExpansion the amount of overexpansion to apply 3772 * @param isFromGesture is this amount from a gesture and needs to be rubberBanded? 3773 */ setOverExpansionInternal(float overExpansion, boolean isFromGesture)3774 private void setOverExpansionInternal(float overExpansion, boolean isFromGesture) { 3775 if (!isFromGesture) { 3776 mLastGesturedOverExpansion = -1; 3777 setOverExpansion(overExpansion); 3778 } else if (mLastGesturedOverExpansion != overExpansion) { 3779 mLastGesturedOverExpansion = overExpansion; 3780 final float heightForFullOvershoot = mView.getHeight() / 3.0f; 3781 float newExpansion = MathUtils.saturate(overExpansion / heightForFullOvershoot); 3782 newExpansion = Interpolators.getOvershootInterpolation(newExpansion); 3783 setOverExpansion(newExpansion * mPanelFlingOvershootAmount * 2.0f); 3784 } 3785 } 3786 3787 /** Sets the expanded height relative to a number from 0 to 1. */ setExpandedFraction(float frac)3788 public void setExpandedFraction(float frac) { 3789 final int maxDist = getMaxPanelTransitionDistance(); 3790 mShadeHeightLogger.logFunctionCall("setExpandedFraction"); 3791 setExpandedHeight(maxDist * frac); 3792 } 3793 getExpandedHeight()3794 float getExpandedHeight() { 3795 return mExpandedHeight; 3796 } 3797 getExpandedFraction()3798 float getExpandedFraction() { 3799 return mExpandedFraction; 3800 } 3801 3802 /** 3803 * This method should not be used anymore, you should probably use {@link #isShadeFullyOpen()} 3804 * instead. It was overused as indicating if shade is open or we're on keyguard/AOD. 3805 * Moving forward we should be explicit about the what state we're checking. 3806 * @return if panel is covering the screen, which means we're in expanded shade or keyguard/AOD 3807 * 3808 * @deprecated depends on the state you check, use {@link #isShadeFullyOpen()}, 3809 * {@link #isOnAod()}, {@link #isOnKeyguard()} instead. 3810 */ 3811 @Deprecated isFullyExpanded()3812 public boolean isFullyExpanded() { 3813 return mExpandedHeight >= getMaxPanelTransitionDistance(); 3814 } 3815 3816 /** 3817 * Returns true if shade is fully opened, that is we're actually in the notification shade 3818 * with QQS or QS. It's different from {@link #isFullyExpanded()} that it will not report 3819 * shade as always expanded if we're on keyguard/AOD. It will return true only when user goes 3820 * from keyguard to shade. 3821 */ isShadeFullyOpen()3822 public boolean isShadeFullyOpen() { 3823 if (mBarState == SHADE) { 3824 return isFullyExpanded(); 3825 } else if (mBarState == SHADE_LOCKED) { 3826 return true; 3827 } else { 3828 // case of two finger swipe from the top of keyguard 3829 return mQsController.computeExpansionFraction() == 1; 3830 } 3831 } 3832 isFullyCollapsed()3833 public boolean isFullyCollapsed() { 3834 return mExpandedFraction <= 0.0f; 3835 } 3836 isCollapsing()3837 public boolean isCollapsing() { 3838 return mClosing || mIsLaunchAnimationRunning; 3839 } 3840 isTracking()3841 public boolean isTracking() { 3842 return mTracking; 3843 } 3844 3845 /** Returns whether the shade can be collapsed. */ canPanelBeCollapsed()3846 public boolean canPanelBeCollapsed() { 3847 return !isFullyCollapsed() && !mTracking && !mClosing; 3848 } 3849 3850 /** Collapses the shade instantly without animation. */ instantCollapse()3851 public void instantCollapse() { 3852 abortAnimations(); 3853 mShadeHeightLogger.logFunctionCall("instantCollapse"); 3854 setExpandedFraction(0f); 3855 if (mExpanding) { 3856 notifyExpandingFinished(); 3857 } 3858 if (mInstantExpanding) { 3859 mInstantExpanding = false; 3860 updatePanelExpansionAndVisibility(); 3861 } 3862 } 3863 abortAnimations()3864 private void abortAnimations() { 3865 cancelHeightAnimator(); 3866 mView.removeCallbacks(mFlingCollapseRunnable); 3867 } 3868 isUnlockHintRunning()3869 public boolean isUnlockHintRunning() { 3870 return mHintAnimationRunning; 3871 } 3872 3873 /** 3874 * Phase 1: Move everything upwards. 3875 */ startUnlockHintAnimationPhase1(final Runnable onAnimationFinished)3876 private void startUnlockHintAnimationPhase1(final Runnable onAnimationFinished) { 3877 float target = Math.max(0, getMaxPanelHeight() - mHintDistance); 3878 ValueAnimator animator = createHeightAnimator(target); 3879 animator.setDuration(250); 3880 animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 3881 animator.addListener(new AnimatorListenerAdapter() { 3882 private boolean mCancelled; 3883 3884 @Override 3885 public void onAnimationCancel(Animator animation) { 3886 mCancelled = true; 3887 } 3888 3889 @Override 3890 public void onAnimationEnd(Animator animation) { 3891 if (mCancelled) { 3892 setAnimator(null); 3893 onAnimationFinished.run(); 3894 } else { 3895 startUnlockHintAnimationPhase2(onAnimationFinished); 3896 } 3897 } 3898 }); 3899 animator.start(); 3900 setAnimator(animator); 3901 3902 final List<ViewPropertyAnimator> indicationAnimators = 3903 mKeyguardBottomArea.getIndicationAreaAnimators(); 3904 for (final ViewPropertyAnimator indicationAreaAnimator : indicationAnimators) { 3905 indicationAreaAnimator 3906 .translationY(-mHintDistance) 3907 .setDuration(250) 3908 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) 3909 .withEndAction(() -> indicationAreaAnimator 3910 .translationY(0) 3911 .setDuration(450) 3912 .setInterpolator(mBounceInterpolator) 3913 .start()) 3914 .start(); 3915 } 3916 } 3917 setAnimator(ValueAnimator animator)3918 private void setAnimator(ValueAnimator animator) { 3919 mHeightAnimator = animator; 3920 if (animator == null && mPanelUpdateWhenAnimatorEnds) { 3921 mPanelUpdateWhenAnimatorEnds = false; 3922 updateExpandedHeightToMaxHeight(); 3923 } 3924 } 3925 3926 /** Returns whether a shade or QS expansion animation is running */ isShadeOrQsHeightAnimationRunning()3927 public boolean isShadeOrQsHeightAnimationRunning() { 3928 return mHeightAnimator != null && !mHintAnimationRunning && !mIsSpringBackAnimation; 3929 } 3930 3931 /** 3932 * Phase 2: Bounce down. 3933 */ startUnlockHintAnimationPhase2(final Runnable onAnimationFinished)3934 private void startUnlockHintAnimationPhase2(final Runnable onAnimationFinished) { 3935 ValueAnimator animator = createHeightAnimator(getMaxPanelHeight()); 3936 animator.setDuration(450); 3937 animator.setInterpolator(mBounceInterpolator); 3938 animator.addListener(new AnimatorListenerAdapter() { 3939 @Override 3940 public void onAnimationEnd(Animator animation) { 3941 setAnimator(null); 3942 onAnimationFinished.run(); 3943 updatePanelExpansionAndVisibility(); 3944 } 3945 }); 3946 animator.start(); 3947 setAnimator(animator); 3948 } 3949 createHeightAnimator(float targetHeight)3950 private ValueAnimator createHeightAnimator(float targetHeight) { 3951 return createHeightAnimator(targetHeight, 0.0f /* performOvershoot */); 3952 } 3953 3954 /** 3955 * Create an animator that can also overshoot 3956 * 3957 * @param targetHeight the target height 3958 * @param overshootAmount the amount of overshoot desired 3959 */ createHeightAnimator(float targetHeight, float overshootAmount)3960 private ValueAnimator createHeightAnimator(float targetHeight, float overshootAmount) { 3961 float startExpansion = mOverExpansion; 3962 ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight); 3963 animator.addUpdateListener( 3964 animation -> { 3965 if (overshootAmount > 0.0f 3966 // Also remove the overExpansion when collapsing 3967 || (targetHeight == 0.0f && startExpansion != 0)) { 3968 final float expansion = MathUtils.lerp( 3969 startExpansion, 3970 mPanelFlingOvershootAmount * overshootAmount, 3971 Interpolators.FAST_OUT_SLOW_IN.getInterpolation( 3972 animator.getAnimatedFraction())); 3973 setOverExpansionInternal(expansion, false /* isFromGesture */); 3974 } 3975 mShadeHeightLogger.logFunctionCall("height animator update"); 3976 setExpandedHeightInternal((float) animation.getAnimatedValue()); 3977 }); 3978 return animator; 3979 } 3980 3981 /** Update the visibility of {@link NotificationPanelView} if necessary. */ updateVisibility()3982 private void updateVisibility() { 3983 mView.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE); 3984 } 3985 3986 /** 3987 * Updates the panel expansion and {@link NotificationPanelView} visibility if necessary. 3988 * 3989 * TODO(b/200063118): Could public calls to this method be replaced with calls to 3990 * {@link #updateVisibility()}? That would allow us to make this method private. 3991 */ updatePanelExpansionAndVisibility()3992 public void updatePanelExpansionAndVisibility() { 3993 mShadeExpansionStateManager.onPanelExpansionChanged( 3994 mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx); 3995 updateVisibility(); 3996 } 3997 isExpanded()3998 public boolean isExpanded() { 3999 return mExpandedFraction > 0f 4000 || mInstantExpanding 4001 || isPanelVisibleBecauseOfHeadsUp() 4002 || mTracking 4003 || mHeightAnimator != null 4004 && !mIsSpringBackAnimation; 4005 } 4006 4007 /** Called when the user performs a click anywhere in the empty area of the panel. */ onEmptySpaceClick()4008 private void onEmptySpaceClick() { 4009 if (!mHintAnimationRunning) { 4010 onMiddleClicked(); 4011 } 4012 } 4013 4014 @VisibleForTesting isClosing()4015 boolean isClosing() { 4016 return mClosing; 4017 } 4018 4019 /** Collapses the shade with an animation duration in milliseconds. */ collapseWithDuration(int animationDuration)4020 public void collapseWithDuration(int animationDuration) { 4021 mFixedDuration = animationDuration; 4022 collapse(false /* delayed */, 1.0f /* speedUpFactor */); 4023 mFixedDuration = NO_FIXED_DURATION; 4024 } 4025 4026 /** Returns the NotificationPanelView. */ getView()4027 public ViewGroup getView() { 4028 // TODO(b/254878364): remove this method, or at least reduce references to it. 4029 return mView; 4030 } 4031 4032 /** */ postToView(Runnable action)4033 public boolean postToView(Runnable action) { 4034 return mView.post(action); 4035 } 4036 4037 /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */ handleExternalInterceptTouch(MotionEvent event)4038 public boolean handleExternalInterceptTouch(MotionEvent event) { 4039 return mTouchHandler.onInterceptTouchEvent(event); 4040 } 4041 4042 /** Sends an external (e.g. Status Bar) touch event to the Shade touch handler. */ handleExternalTouch(MotionEvent event)4043 public boolean handleExternalTouch(MotionEvent event) { 4044 return mTouchHandler.onTouchEvent(event); 4045 } 4046 4047 /** */ requestLayoutOnView()4048 public void requestLayoutOnView() { 4049 mView.requestLayout(); 4050 } 4051 4052 /** */ resetViewAlphas()4053 public void resetViewAlphas() { 4054 ViewGroupFadeHelper.reset(mView); 4055 } 4056 4057 /** */ isViewEnabled()4058 public boolean isViewEnabled() { 4059 return mView.isEnabled(); 4060 } 4061 getOverStretchAmount()4062 float getOverStretchAmount() { 4063 return mOverStretchAmount; 4064 } 4065 getMinFraction()4066 float getMinFraction() { 4067 return mMinFraction; 4068 } 4069 getNavigationBarBottomHeight()4070 int getNavigationBarBottomHeight() { 4071 return mNavigationBarBottomHeight; 4072 } 4073 isExpandingFromHeadsUp()4074 boolean isExpandingFromHeadsUp() { 4075 return mExpandingFromHeadsUp; 4076 } 4077 4078 /** 4079 * We don't always want to close QS when requested as shade might be in a different state 4080 * already e.g. when going from collapse to expand very quickly. In that case StatusBar 4081 * window might send signal to collapse QS but we might be already expanding and in split 4082 * shade QS are always expanded 4083 */ closeQsIfPossible()4084 private void closeQsIfPossible() { 4085 boolean openOrOpening = isShadeFullyOpen() || isExpanding(); 4086 if (!(mSplitShadeEnabled && openOrOpening)) { 4087 mQsController.closeQs(); 4088 } 4089 } 4090 4091 /** TODO: remove need for this delegate (b/254870148) */ setQsScrimEnabled(boolean qsScrimEnabled)4092 public void setQsScrimEnabled(boolean qsScrimEnabled) { 4093 mQsController.setScrimEnabled(qsScrimEnabled); 4094 } 4095 getShadeExpansionStateManager()4096 private ShadeExpansionStateManager getShadeExpansionStateManager() { 4097 return mShadeExpansionStateManager; 4098 } 4099 onQsExpansionChanged(boolean expanded)4100 private void onQsExpansionChanged(boolean expanded) { 4101 updateExpandedHeightToMaxHeight(); 4102 setStatusAccessibilityImportance(expanded 4103 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 4104 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); 4105 updateSystemUiStateFlags(); 4106 NavigationBarView navigationBarView = 4107 mNavigationBarController.getNavigationBarView(mDisplayId); 4108 if (navigationBarView != null) { 4109 navigationBarView.onStatusBarPanelStateChanged(); 4110 } 4111 } 4112 4113 @VisibleForTesting onQsSetExpansionHeightCalled(boolean qsFullyExpanded)4114 void onQsSetExpansionHeightCalled(boolean qsFullyExpanded) { 4115 requestScrollerTopPaddingUpdate(false); 4116 mKeyguardStatusBarViewController.updateViewState(); 4117 int barState = getBarState(); 4118 if (barState == SHADE_LOCKED || barState == KEYGUARD) { 4119 updateKeyguardBottomAreaAlpha(); 4120 positionClockAndNotifications(); 4121 } 4122 4123 if (mAccessibilityManager.isEnabled()) { 4124 mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); 4125 } 4126 4127 if (!mFalsingManager.isUnlockingDisabled() && qsFullyExpanded 4128 && mFalsingCollector.shouldEnforceBouncer()) { 4129 mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, 4130 false, true, false); 4131 } 4132 if (DEBUG_DRAWABLE) { 4133 mView.invalidate(); 4134 } 4135 } 4136 onQsStateUpdated(boolean qsExpanded, boolean isStackScrollerOverscrolling)4137 private void onQsStateUpdated(boolean qsExpanded, boolean isStackScrollerOverscrolling) { 4138 if (mKeyguardUserSwitcherController != null && qsExpanded 4139 && !isStackScrollerOverscrolling) { 4140 mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(true); 4141 } 4142 } 4143 onQsClippingImmediatelyApplied(boolean clipStatusView, Rect lastQsClipBounds, int top, boolean qsFragmentCreated, boolean qsVisible)4144 private void onQsClippingImmediatelyApplied(boolean clipStatusView, 4145 Rect lastQsClipBounds, int top, boolean qsFragmentCreated, boolean qsVisible) { 4146 if (qsFragmentCreated) { 4147 mKeyguardInteractor.setQuickSettingsVisible(qsVisible); 4148 } 4149 4150 // The padding on this area is large enough that 4151 // we can use a cheaper clipping strategy 4152 mKeyguardStatusViewController.setClipBounds( 4153 clipStatusView ? lastQsClipBounds : null); 4154 if (mSplitShadeEnabled) { 4155 mKeyguardStatusBarViewController.setNoTopClipping(); 4156 } else { 4157 mKeyguardStatusBarViewController.updateTopClipping(top); 4158 } 4159 } 4160 onFlingQsWithoutClick(ValueAnimator animator, float qsExpansionHeight, float target, float vel)4161 private void onFlingQsWithoutClick(ValueAnimator animator, float qsExpansionHeight, 4162 float target, float vel) { 4163 mFlingAnimationUtils.apply(animator, qsExpansionHeight, target, vel); 4164 } 4165 onExpansionHeightSetToMax(boolean requestPaddingUpdate)4166 private void onExpansionHeightSetToMax(boolean requestPaddingUpdate) { 4167 if (requestPaddingUpdate) { 4168 requestScrollerTopPaddingUpdate(false /* animate */); 4169 } 4170 updateExpandedHeightToMaxHeight(); 4171 } 4172 4173 private final class NsslHeightChangedListener implements 4174 ExpandableView.OnHeightChangedListener { 4175 @Override onHeightChanged(ExpandableView view, boolean needsAnimation)4176 public void onHeightChanged(ExpandableView view, boolean needsAnimation) { 4177 // Block update if we are in QS and just the top padding changed (i.e. view == null). 4178 if (view == null && mQsController.getExpanded()) { 4179 return; 4180 } 4181 if (needsAnimation && mInterpolatedDarkAmount == 0) { 4182 mAnimateNextPositionUpdate = true; 4183 } 4184 ExpandableView firstChildNotGone = 4185 mNotificationStackScrollLayoutController.getFirstChildNotGone(); 4186 ExpandableNotificationRow 4187 firstRow = 4188 firstChildNotGone instanceof ExpandableNotificationRow 4189 ? (ExpandableNotificationRow) firstChildNotGone : null; 4190 if (firstRow != null && (view == firstRow || (firstRow.getNotificationParent() 4191 == firstRow))) { 4192 requestScrollerTopPaddingUpdate(false /* animate */); 4193 } 4194 if (getKeyguardShowing()) { 4195 updateMaxDisplayedNotifications(true); 4196 } 4197 updateExpandedHeightToMaxHeight(); 4198 } 4199 4200 @Override onReset(ExpandableView view)4201 public void onReset(ExpandableView view) {} 4202 } 4203 onDynamicPrivacyChanged()4204 private void onDynamicPrivacyChanged() { 4205 // Do not request animation when pulsing or waking up, otherwise the clock will be out 4206 // of sync with the notification panel. 4207 if (mLinearDarkAmount != 0) { 4208 return; 4209 } 4210 mAnimateNextPositionUpdate = true; 4211 } 4212 4213 private final class ShadeHeadsUpChangedListener implements OnHeadsUpChangedListener { 4214 @Override onHeadsUpPinnedModeChanged(final boolean inPinnedMode)4215 public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) { 4216 if (inPinnedMode) { 4217 mHeadsUpExistenceChangedRunnable.run(); 4218 updateNotificationTranslucency(); 4219 } else { 4220 setHeadsUpAnimatingAway(true); 4221 mNotificationStackScrollLayoutController.runAfterAnimationFinished( 4222 mHeadsUpExistenceChangedRunnable); 4223 } 4224 updateGestureExclusionRect(); 4225 mHeadsUpPinnedMode = inPinnedMode; 4226 updateVisibility(); 4227 mKeyguardStatusBarViewController.updateForHeadsUp(); 4228 } 4229 4230 @Override onHeadsUpPinned(NotificationEntry entry)4231 public void onHeadsUpPinned(NotificationEntry entry) { 4232 if (!isOnKeyguard()) { 4233 mNotificationStackScrollLayoutController.generateHeadsUpAnimation( 4234 entry.getHeadsUpAnimationView(), true); 4235 } 4236 } 4237 4238 @Override onHeadsUpUnPinned(NotificationEntry entry)4239 public void onHeadsUpUnPinned(NotificationEntry entry) { 4240 4241 // When we're unpinning the notification via active edge they remain heads-upped, 4242 // we need to make sure that an animation happens in this case, otherwise the 4243 // notification 4244 // will stick to the top without any interaction. 4245 if (isFullyCollapsed() && entry.isRowHeadsUp() && !isOnKeyguard()) { 4246 mNotificationStackScrollLayoutController.generateHeadsUpAnimation( 4247 entry.getHeadsUpAnimationView(), false); 4248 entry.setHeadsUpIsVisible(); 4249 } 4250 } 4251 } 4252 4253 private final class ConfigurationListener implements 4254 ConfigurationController.ConfigurationListener { 4255 @Override onThemeChanged()4256 public void onThemeChanged() { 4257 debugLog("onThemeChanged"); 4258 reInflateViews(); 4259 } 4260 4261 @Override onSmallestScreenWidthChanged()4262 public void onSmallestScreenWidthChanged() { 4263 Trace.beginSection("onSmallestScreenWidthChanged"); 4264 debugLog("onSmallestScreenWidthChanged"); 4265 4266 // Can affect multi-user switcher visibility as it depends on screen size by default: 4267 // it is enabled only for devices with large screens (see config_keyguardUserSwitcher) 4268 boolean prevKeyguardUserSwitcherEnabled = mKeyguardUserSwitcherEnabled; 4269 boolean prevKeyguardQsUserSwitchEnabled = mKeyguardQsUserSwitchEnabled; 4270 updateUserSwitcherFlags(); 4271 if (prevKeyguardUserSwitcherEnabled != mKeyguardUserSwitcherEnabled 4272 || prevKeyguardQsUserSwitchEnabled != mKeyguardQsUserSwitchEnabled) { 4273 reInflateViews(); 4274 } 4275 4276 Trace.endSection(); 4277 } 4278 4279 @Override onDensityOrFontScaleChanged()4280 public void onDensityOrFontScaleChanged() { 4281 debugLog("onDensityOrFontScaleChanged"); 4282 reInflateViews(); 4283 } 4284 } 4285 4286 private final class SettingsChangeObserver extends ContentObserver { SettingsChangeObserver(Handler handler)4287 SettingsChangeObserver(Handler handler) { 4288 super(handler); 4289 } 4290 4291 @Override onChange(boolean selfChange)4292 public void onChange(boolean selfChange) { 4293 debugLog("onSettingsChanged"); 4294 4295 // Can affect multi-user switcher visibility 4296 reInflateViews(); 4297 } 4298 } 4299 4300 private final class StatusBarStateListener implements StateListener { 4301 @Override onStateChanged(int statusBarState)4302 public void onStateChanged(int statusBarState) { 4303 boolean goingToFullShade = mStatusBarStateController.goingToFullShade(); 4304 boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway(); 4305 int oldState = mBarState; 4306 boolean keyguardShowing = statusBarState == KEYGUARD; 4307 4308 if (mDozeParameters.shouldDelayKeyguardShow() 4309 && oldState == StatusBarState.SHADE 4310 && statusBarState == KEYGUARD) { 4311 // This means we're doing the screen off animation - position the keyguard status 4312 // view where it'll be on AOD, so we can animate it in. 4313 mKeyguardStatusViewController.updatePosition( 4314 mClockPositionResult.clockX, 4315 mClockPositionResult.clockYFullyDozing, 4316 mClockPositionResult.clockScale, 4317 false /* animate */); 4318 } 4319 4320 mKeyguardStatusViewController.setKeyguardStatusViewVisibility( 4321 statusBarState, 4322 keyguardFadingAway, 4323 goingToFullShade, 4324 mBarState); 4325 4326 setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade); 4327 4328 // TODO: maybe add a listener for barstate 4329 mBarState = statusBarState; 4330 mQsController.setBarState(statusBarState); 4331 4332 boolean fromShadeToKeyguard = statusBarState == KEYGUARD 4333 && (oldState == SHADE || oldState == SHADE_LOCKED); 4334 if (mSplitShadeEnabled && fromShadeToKeyguard) { 4335 // user can go to keyguard from different shade states and closing animation 4336 // may not fully run - we always want to make sure we close QS when that happens 4337 // as we never need QS open in fresh keyguard state 4338 mQsController.closeQs(); 4339 } 4340 4341 if (oldState == KEYGUARD && (goingToFullShade 4342 || statusBarState == StatusBarState.SHADE_LOCKED)) { 4343 4344 long startDelay; 4345 long duration; 4346 if (mKeyguardStateController.isKeyguardFadingAway()) { 4347 startDelay = mKeyguardStateController.getKeyguardFadingAwayDelay(); 4348 duration = mKeyguardStateController.getShortenedFadingAwayDuration(); 4349 } else { 4350 startDelay = 0; 4351 duration = StackStateAnimator.ANIMATION_DURATION_STANDARD; 4352 } 4353 mKeyguardStatusBarViewController.animateKeyguardStatusBarOut(startDelay, duration); 4354 mQsController.updateMinHeight(); 4355 } else if (oldState == StatusBarState.SHADE_LOCKED 4356 && statusBarState == KEYGUARD) { 4357 mKeyguardStatusBarViewController.animateKeyguardStatusBarIn(); 4358 4359 mNotificationStackScrollLayoutController.resetScrollPosition(); 4360 } else { 4361 // this else branch means we are doing one of: 4362 // - from KEYGUARD to SHADE (but not fully expanded as when swiping from the top) 4363 // - from SHADE to KEYGUARD 4364 // - from SHADE_LOCKED to SHADE 4365 // - getting notified again about the current SHADE or KEYGUARD state 4366 final boolean animatingUnlockedShadeToKeyguard = oldState == SHADE 4367 && statusBarState == KEYGUARD 4368 && mScreenOffAnimationController.isKeyguardShowDelayed(); 4369 if (!animatingUnlockedShadeToKeyguard) { 4370 // Only make the status bar visible if we're not animating the screen off, since 4371 // we only want to be showing the clock/notifications during the animation. 4372 if (keyguardShowing) { 4373 mShadeLog.v("Updating keyguard status bar state to visible"); 4374 } else { 4375 mShadeLog.v("Updating keyguard status bar state to invisible"); 4376 } 4377 mKeyguardStatusBarViewController.updateViewState( 4378 /* alpha= */ 1f, 4379 keyguardShowing ? View.VISIBLE : View.INVISIBLE); 4380 } 4381 if (keyguardShowing && oldState != mBarState) { 4382 mQsController.hideQsImmediately(); 4383 } 4384 } 4385 mKeyguardStatusBarViewController.updateForHeadsUp(); 4386 if (keyguardShowing) { 4387 updateDozingVisibilities(false /* animate */); 4388 } 4389 4390 updateMaxDisplayedNotifications(false); 4391 // The update needs to happen after the headerSlide in above, otherwise the translation 4392 // would reset 4393 maybeAnimateBottomAreaAlpha(); 4394 mQsController.updateQsState(); 4395 } 4396 4397 @Override onDozeAmountChanged(float linearAmount, float amount)4398 public void onDozeAmountChanged(float linearAmount, float amount) { 4399 mInterpolatedDarkAmount = amount; 4400 mLinearDarkAmount = linearAmount; 4401 positionClockAndNotifications(); 4402 } 4403 } 4404 4405 /** 4406 * An interface that provides the current state of the notification panel and related views, 4407 * which is needed to calculate {@link KeyguardStatusBarView}'s state in 4408 * {@link KeyguardStatusBarViewController}. 4409 */ 4410 public interface NotificationPanelViewStateProvider { 4411 /** Returns the expanded height of the panel view. */ getPanelViewExpandedHeight()4412 float getPanelViewExpandedHeight(); 4413 4414 /** 4415 * Returns true if heads up should be visible. 4416 * 4417 * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into 4418 * {@link KeyguardStatusBarViewController} and remove this method. 4419 */ shouldHeadsUpBeVisible()4420 boolean shouldHeadsUpBeVisible(); 4421 4422 /** Return the fraction of the shade that's expanded, when in lockscreen. */ getLockscreenShadeDragProgress()4423 float getLockscreenShadeDragProgress(); 4424 } 4425 4426 private final NotificationPanelViewStateProvider mNotificationPanelViewStateProvider = 4427 new NotificationPanelViewStateProvider() { 4428 @Override 4429 public float getPanelViewExpandedHeight() { 4430 return getExpandedHeight(); 4431 } 4432 4433 @Override 4434 public boolean shouldHeadsUpBeVisible() { 4435 return mHeadsUpAppearanceController.shouldBeVisible(); 4436 } 4437 4438 @Override 4439 public float getLockscreenShadeDragProgress() { 4440 return NotificationPanelViewController.this.getLockscreenShadeDragProgress(); 4441 } 4442 }; 4443 4444 /** 4445 * Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the 4446 * screen off animation controller in order to animate in AOD without "actually" fully switching 4447 * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the 4448 * change. 4449 */ showAodUi()4450 public void showAodUi() { 4451 setDozing(true /* dozing */, false /* animate */); 4452 mStatusBarStateController.setUpcomingState(KEYGUARD); 4453 mStatusBarStateListener.onStateChanged(KEYGUARD); 4454 mStatusBarStateListener.onDozeAmountChanged(1f, 1f); 4455 mShadeHeightLogger.logFunctionCall("showAodUi"); 4456 setExpandedFraction(1f); 4457 } 4458 4459 /** Sets the overstretch amount in raw pixels when dragging down. */ setOverStretchAmount(float amount)4460 public void setOverStretchAmount(float amount) { 4461 float progress = amount / mView.getHeight(); 4462 float overStretch = Interpolators.getOvershootInterpolation(progress); 4463 mOverStretchAmount = overStretch * mMaxOverscrollAmountForPulse; 4464 positionClockAndNotifications(true /* forceUpdate */); 4465 } 4466 4467 private final class ShadeAttachStateChangeListener implements View.OnAttachStateChangeListener { 4468 @Override onViewAttachedToWindow(View v)4469 public void onViewAttachedToWindow(View v) { 4470 mFragmentService.getFragmentHostManager(mView) 4471 .addTagListener(QS.TAG, mQsController.getQsFragmentListener()); 4472 mStatusBarStateController.addCallback(mStatusBarStateListener); 4473 mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState()); 4474 mConfigurationController.addCallback(mConfigurationListener); 4475 // Theme might have changed between inflating this view and attaching it to the 4476 // window, so 4477 // force a call to onThemeChanged 4478 mConfigurationListener.onThemeChanged(); 4479 mFalsingManager.addTapListener(mFalsingTapListener); 4480 mKeyguardIndicationController.init(); 4481 registerSettingsChangeListener(); 4482 } 4483 4484 @Override onViewDetachedFromWindow(View v)4485 public void onViewDetachedFromWindow(View v) { 4486 mContentResolver.unregisterContentObserver(mSettingsChangeObserver); 4487 mFragmentService.getFragmentHostManager(mView) 4488 .removeTagListener(QS.TAG, mQsController.getQsFragmentListener()); 4489 mStatusBarStateController.removeCallback(mStatusBarStateListener); 4490 mConfigurationController.removeCallback(mConfigurationListener); 4491 mFalsingManager.removeTapListener(mFalsingTapListener); 4492 } 4493 } 4494 4495 private final class ShadeLayoutChangeListener implements View.OnLayoutChangeListener { 4496 @Override onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)4497 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, 4498 int oldTop, int oldRight, int oldBottom) { 4499 DejankUtils.startDetectingBlockingIpcs("NVP#onLayout"); 4500 updateExpandedHeightToMaxHeight(); 4501 mHasLayoutedSinceDown = true; 4502 if (mUpdateFlingOnLayout) { 4503 abortAnimations(); 4504 fling(mUpdateFlingVelocity); 4505 mUpdateFlingOnLayout = false; 4506 } 4507 updateMaxDisplayedNotifications(!shouldAvoidChangingNotificationsCount()); 4508 setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth()); 4509 4510 // Update Clock Pivot (used by anti-burnin transformations) 4511 mKeyguardStatusViewController.updatePivot(mView.getWidth(), mView.getHeight()); 4512 4513 int oldMaxHeight = mQsController.updateHeightsOnShadeLayoutChange(); 4514 positionClockAndNotifications(); 4515 mQsController.handleShadeLayoutChanged(oldMaxHeight); 4516 updateExpandedHeight(getExpandedHeight()); 4517 updateHeader(); 4518 4519 // If we are running a size change animation, the animation takes care of the height 4520 // of the container. However, if we are not animating, we always need to make the QS 4521 // container the desired height so when closing the QS detail, it stays smaller after 4522 // the size change animation is finished but the detail view is still being animated 4523 // away (this animation takes longer than the size change animation). 4524 mQsController.setHeightOverrideToDesiredHeight(); 4525 4526 updateMaxHeadsUpTranslation(); 4527 updateGestureExclusionRect(); 4528 if (mExpandAfterLayoutRunnable != null) { 4529 mExpandAfterLayoutRunnable.run(); 4530 mExpandAfterLayoutRunnable = null; 4531 } 4532 DejankUtils.stopDetectingBlockingIpcs("NVP#onLayout"); 4533 } 4534 } 4535 4536 @NonNull onApplyShadeWindowInsets(WindowInsets insets)4537 private WindowInsets onApplyShadeWindowInsets(WindowInsets insets) { 4538 // the same types of insets that are handled in NotificationShadeWindowView 4539 int insetTypes = WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout(); 4540 Insets combinedInsets = insets.getInsetsIgnoringVisibility(insetTypes); 4541 mDisplayTopInset = combinedInsets.top; 4542 mDisplayRightInset = combinedInsets.right; 4543 mDisplayLeftInset = combinedInsets.left; 4544 mQsController.setDisplayInsets(mDisplayRightInset, mDisplayLeftInset); 4545 4546 mNavigationBarBottomHeight = insets.getStableInsetBottom(); 4547 updateMaxHeadsUpTranslation(); 4548 return insets; 4549 } 4550 4551 /** Removes any pending runnables that would collapse the panel. */ cancelPendingPanelCollapse()4552 public void cancelPendingPanelCollapse() { 4553 mView.removeCallbacks(mMaybeHideExpandedRunnable); 4554 } 4555 onPanelStateChanged(@anelState int state)4556 private void onPanelStateChanged(@PanelState int state) { 4557 mQsController.updateExpansionEnabledAmbient(); 4558 4559 if (state == STATE_OPEN && mCurrentPanelState != state) { 4560 mQsController.setExpandImmediate(false); 4561 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 4562 } 4563 if (state == STATE_OPENING) { 4564 // we need to ignore it on keyguard as this is a false alarm - transition from unlocked 4565 // to locked will trigger this event and we're not actually in the process of opening 4566 // the shade, lockscreen is just always expanded 4567 if (mSplitShadeEnabled && !isOnKeyguard()) { 4568 mQsController.setExpandImmediate(true); 4569 } 4570 mOpenCloseListener.onOpenStarted(); 4571 } 4572 if (state == STATE_CLOSED) { 4573 mQsController.setExpandImmediate(false); 4574 // Close the status bar in the next frame so we can show the end of the 4575 // animation. 4576 mView.post(mMaybeHideExpandedRunnable); 4577 } 4578 mCurrentPanelState = state; 4579 } 4580 setTransitionAlpha( NotificationStackScrollLayoutController stackScroller)4581 private Consumer<Float> setTransitionAlpha( 4582 NotificationStackScrollLayoutController stackScroller) { 4583 return (Float alpha) -> { 4584 mKeyguardStatusViewController.setAlpha(alpha); 4585 stackScroller.setAlpha(alpha); 4586 4587 mKeyguardBottomAreaInteractor.setAlpha(alpha); 4588 mLockIconViewController.setAlpha(alpha); 4589 4590 if (mKeyguardQsUserSwitchController != null) { 4591 mKeyguardQsUserSwitchController.setAlpha(alpha); 4592 } 4593 if (mKeyguardUserSwitcherController != null) { 4594 mKeyguardUserSwitcherController.setAlpha(alpha); 4595 } 4596 }; 4597 } 4598 4599 private Consumer<Float> setTransitionY( 4600 NotificationStackScrollLayoutController stackScroller) { 4601 return (Float translationY) -> { 4602 mKeyguardStatusViewController.setTranslationY(translationY, /* excludeMedia= */false); 4603 stackScroller.setTranslationY(translationY); 4604 }; 4605 } 4606 4607 @VisibleForTesting 4608 StatusBarStateController getStatusBarStateController() { 4609 return mStatusBarStateController; 4610 } 4611 4612 @VisibleForTesting 4613 StateListener getStatusBarStateListener() { 4614 return mStatusBarStateListener; 4615 } 4616 4617 @VisibleForTesting 4618 boolean isHintAnimationRunning() { 4619 return mHintAnimationRunning; 4620 } 4621 4622 private void onStatusBarWindowStateChanged(@StatusBarManager.WindowVisibleState int state) { 4623 if (state != WINDOW_STATE_SHOWING 4624 && mStatusBarStateController.getState() == StatusBarState.SHADE) { 4625 collapsePanel( 4626 false /* animate */, 4627 false /* delayed */, 4628 1.0f /* speedUpFactor */); 4629 } 4630 } 4631 4632 /** Handles MotionEvents for the Shade. */ 4633 public final class TouchHandler implements View.OnTouchListener, Gefingerpoken { 4634 private long mLastTouchDownTime = -1L; 4635 4636 /** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */ 4637 public boolean onInterceptTouchEvent(MotionEvent event) { 4638 mShadeLog.logMotionEvent(event, "NPVC onInterceptTouchEvent"); 4639 if (mQsController.disallowTouches()) { 4640 mShadeLog.logMotionEvent(event, 4641 "NPVC not intercepting touch, panel touches disallowed"); 4642 return false; 4643 } 4644 initDownStates(event); 4645 // Do not let touches go to shade or QS if the bouncer is visible, 4646 // but still let user swipe down to expand the panel, dismissing the bouncer. 4647 if (mCentralSurfaces.isBouncerShowing()) { 4648 mShadeLog.v("NotificationPanelViewController MotionEvent intercepted: " 4649 + "bouncer is showing"); 4650 return true; 4651 } 4652 if (mCommandQueue.panelsEnabled() 4653 && !mNotificationStackScrollLayoutController.isLongPressInProgress() 4654 && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) { 4655 mMetricsLogger.count(COUNTER_PANEL_OPEN, 1); 4656 mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1); 4657 mShadeLog.v("NotificationPanelViewController MotionEvent intercepted: " 4658 + "HeadsUpTouchHelper"); 4659 return true; 4660 } 4661 if (!mQsController.shouldQuickSettingsIntercept(mDownX, mDownY, 0) 4662 && mPulseExpansionHandler.onInterceptTouchEvent(event)) { 4663 mShadeLog.v("NotificationPanelViewController MotionEvent intercepted: " 4664 + "PulseExpansionHandler"); 4665 return true; 4666 } 4667 4668 if (!isFullyCollapsed() && mQsController.onIntercept(event)) { 4669 debugLog("onQsIntercept true"); 4670 mShadeLog.v("NotificationPanelViewController MotionEvent intercepted: " 4671 + "QsIntercept"); 4672 return true; 4673 } 4674 4675 if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled) { 4676 mShadeLog.logNotInterceptingTouchInstantExpanding(mInstantExpanding, 4677 !mNotificationsDragEnabled, mTouchDisabled); 4678 return false; 4679 } 4680 if (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN) { 4681 mShadeLog.logMotionEventStatusBarState(event, mStatusBarStateController.getState(), 4682 "NPVC MotionEvent not intercepted: non-down action, motion was aborted"); 4683 return false; 4684 } 4685 4686 /* If the user drags anywhere inside the panel we intercept it if the movement is 4687 upwards. This allows closing the shade from anywhere inside the panel. 4688 We only do this if the current content is scrolled to the bottom, i.e. 4689 canCollapsePanelOnTouch() is true and therefore there is no conflicting scrolling 4690 gesture possible. */ 4691 int pointerIndex = event.findPointerIndex(mTrackingPointer); 4692 if (pointerIndex < 0) { 4693 pointerIndex = 0; 4694 mTrackingPointer = event.getPointerId(pointerIndex); 4695 } 4696 final float x = event.getX(pointerIndex); 4697 final float y = event.getY(pointerIndex); 4698 boolean canCollapsePanel = canCollapsePanelOnTouch(); 4699 4700 switch (event.getActionMasked()) { 4701 case MotionEvent.ACTION_DOWN: 4702 mCentralSurfaces.userActivity(); 4703 mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation; 4704 mMinExpandHeight = 0.0f; 4705 mDownTime = mSystemClock.uptimeMillis(); 4706 if (mAnimatingOnDown && mClosing && !mHintAnimationRunning) { 4707 cancelHeightAnimator(); 4708 mTouchSlopExceeded = true; 4709 mShadeLog.v("NotificationPanelViewController MotionEvent intercepted:" 4710 + " mAnimatingOnDown: true, mClosing: true, mHintAnimationRunning:" 4711 + " false"); 4712 return true; 4713 } 4714 if (!mTracking || isFullyCollapsed()) { 4715 mInitialExpandY = y; 4716 mInitialExpandX = x; 4717 } else { 4718 mShadeLog.d("not setting mInitialExpandY in onInterceptTouch"); 4719 } 4720 mTouchStartedInEmptyArea = !isInContentBounds(x, y); 4721 mTouchSlopExceeded = mTouchSlopExceededBeforeDown; 4722 mMotionAborted = false; 4723 mPanelClosedOnDown = isFullyCollapsed(); 4724 mCollapsedAndHeadsUpOnDown = false; 4725 mHasLayoutedSinceDown = false; 4726 mUpdateFlingOnLayout = false; 4727 mTouchAboveFalsingThreshold = false; 4728 addMovement(event); 4729 break; 4730 case MotionEvent.ACTION_POINTER_UP: 4731 final int upPointer = event.getPointerId(event.getActionIndex()); 4732 if (mTrackingPointer == upPointer) { 4733 // gesture is ongoing, find a new pointer to track 4734 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1; 4735 mTrackingPointer = event.getPointerId(newIndex); 4736 mInitialExpandX = event.getX(newIndex); 4737 mInitialExpandY = event.getY(newIndex); 4738 } 4739 break; 4740 case MotionEvent.ACTION_POINTER_DOWN: 4741 mShadeLog.logMotionEventStatusBarState(event, 4742 mStatusBarStateController.getState(), 4743 "onInterceptTouchEvent: pointer down action"); 4744 if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { 4745 mMotionAborted = true; 4746 mVelocityTracker.clear(); 4747 } 4748 break; 4749 case MotionEvent.ACTION_MOVE: 4750 final float h = y - mInitialExpandY; 4751 addMovement(event); 4752 final boolean openShadeWithoutHun = 4753 mPanelClosedOnDown && !mCollapsedAndHeadsUpOnDown; 4754 if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown 4755 || openShadeWithoutHun) { 4756 float hAbs = Math.abs(h); 4757 float touchSlop = getTouchSlop(event); 4758 if ((h < -touchSlop 4759 || ((openShadeWithoutHun || mAnimatingOnDown) && hAbs > touchSlop)) 4760 && hAbs > Math.abs(x - mInitialExpandX)) { 4761 cancelHeightAnimator(); 4762 startExpandMotion(x, y, true /* startTracking */, mExpandedHeight); 4763 mShadeLog.v("NotificationPanelViewController MotionEvent" 4764 + " intercepted: startExpandMotion"); 4765 return true; 4766 } 4767 } 4768 break; 4769 case MotionEvent.ACTION_CANCEL: 4770 case MotionEvent.ACTION_UP: 4771 mVelocityTracker.clear(); 4772 break; 4773 } 4774 return false; 4775 } 4776 4777 @Override 4778 public boolean onTouch(View v, MotionEvent event) { 4779 return onTouchEvent(event); 4780 } 4781 4782 @Override 4783 public boolean onTouchEvent(MotionEvent event) { 4784 if (event.getAction() == MotionEvent.ACTION_DOWN) { 4785 if (event.getDownTime() == mLastTouchDownTime) { 4786 // An issue can occur when swiping down after unlock, where multiple down 4787 // events are received in this handler with identical downTimes. Until the 4788 // source of the issue can be located, detect this case and ignore. 4789 // see b/193350347 4790 mShadeLog.logMotionEvent(event, 4791 "onTouch: duplicate down event detected... ignoring"); 4792 return true; 4793 } 4794 mLastTouchDownTime = event.getDownTime(); 4795 } 4796 4797 if (mQsController.isFullyExpandedAndTouchesDisallowed()) { 4798 mShadeLog.logMotionEvent(event, 4799 "onTouch: ignore touch, panel touches disallowed and qs fully expanded"); 4800 return false; 4801 } 4802 4803 // Do not allow panel expansion if bouncer is scrimmed or showing over a dream, 4804 // otherwise user would be able to pull down QS or expand the shade. 4805 if (mCentralSurfaces.isBouncerShowingScrimmed() 4806 || mCentralSurfaces.isBouncerShowingOverDream()) { 4807 mShadeLog.logMotionEvent(event, 4808 "onTouch: ignore touch, bouncer scrimmed or showing over dream"); 4809 return false; 4810 } 4811 4812 // Make sure the next touch won't the blocked after the current ends. 4813 if (event.getAction() == MotionEvent.ACTION_UP 4814 || event.getAction() == MotionEvent.ACTION_CANCEL) { 4815 mBlockingExpansionForCurrentTouch = false; 4816 } 4817 // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately 4818 // without any ACTION_MOVE event. 4819 // In such case, simply expand the panel instead of being stuck at the bottom bar. 4820 if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) { 4821 expand(true /* animate */); 4822 } 4823 initDownStates(event); 4824 4825 // If pulse is expanding already, let's give it the touch. There are situations 4826 // where the panel starts expanding even though we're also pulsing 4827 boolean pulseShouldGetTouch = (!mIsExpanding 4828 && !mQsController.shouldQuickSettingsIntercept(mDownX, mDownY, 0)) 4829 || mPulseExpansionHandler.isExpanding(); 4830 if (pulseShouldGetTouch && mPulseExpansionHandler.onTouchEvent(event)) { 4831 // We're expanding all the other ones shouldn't get this anymore 4832 mShadeLog.logMotionEvent(event, "onTouch: PulseExpansionHandler handled event"); 4833 return true; 4834 } 4835 if (mPulsing) { 4836 mShadeLog.logMotionEvent(event, "onTouch: eat touch, device pulsing"); 4837 return true; 4838 } 4839 if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp() 4840 && !mNotificationStackScrollLayoutController.isLongPressInProgress() 4841 && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) { 4842 mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1); 4843 } 4844 boolean handled = mHeadsUpTouchHelper.onTouchEvent(event); 4845 4846 if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch( 4847 event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) { 4848 mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event"); 4849 return true; 4850 } 4851 if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { 4852 mMetricsLogger.count(COUNTER_PANEL_OPEN, 1); 4853 handled = true; 4854 } 4855 4856 if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyExpanded() 4857 && mKeyguardStateController.isShowing()) { 4858 mStatusBarKeyguardViewManager.updateKeyguardPosition(event.getX()); 4859 } 4860 4861 handled |= handleTouch(event); 4862 return !mDozing || handled; 4863 } 4864 4865 private boolean handleTouch(MotionEvent event) { 4866 if (mInstantExpanding) { 4867 mShadeLog.logMotionEvent(event, 4868 "handleTouch: touch ignored due to instant expanding"); 4869 return false; 4870 } 4871 if (mTouchDisabled && event.getActionMasked() != MotionEvent.ACTION_CANCEL) { 4872 mShadeLog.logMotionEvent(event, "handleTouch: non-cancel action, touch disabled"); 4873 return false; 4874 } 4875 if (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN) { 4876 mShadeLog.logMotionEventStatusBarState(event, mStatusBarStateController.getState(), 4877 "handleTouch: non-down action, motion was aborted"); 4878 return false; 4879 } 4880 4881 // If dragging should not expand the notifications shade, then return false. 4882 if (!mNotificationsDragEnabled) { 4883 if (mTracking) { 4884 // Turn off tracking if it's on or the shade can get stuck in the down position. 4885 onTrackingStopped(true /* expand */); 4886 } 4887 mShadeLog.logMotionEvent(event, "handleTouch: drag not enabled"); 4888 return false; 4889 } 4890 4891 // On expanding, single mouse click expands the panel instead of dragging. 4892 if (isFullyCollapsed() && event.isFromSource(InputDevice.SOURCE_MOUSE)) { 4893 if (event.getAction() == MotionEvent.ACTION_UP) { 4894 expand(true); 4895 } 4896 return true; 4897 } 4898 4899 /* 4900 * We capture touch events here and update the expand height here in case according to 4901 * the users fingers. This also handles multi-touch. 4902 * 4903 * Flinging is also enabled in order to open or close the shade. 4904 */ 4905 int pointerIndex = event.findPointerIndex(mTrackingPointer); 4906 if (pointerIndex < 0) { 4907 pointerIndex = 0; 4908 mTrackingPointer = event.getPointerId(pointerIndex); 4909 } 4910 final float x = event.getX(pointerIndex); 4911 final float y = event.getY(pointerIndex); 4912 4913 if (event.getActionMasked() == MotionEvent.ACTION_DOWN 4914 || event.getActionMasked() == MotionEvent.ACTION_MOVE) { 4915 mGestureWaitForTouchSlop = shouldGestureWaitForTouchSlop(); 4916 mIgnoreXTouchSlop = true; 4917 } 4918 4919 switch (event.getActionMasked()) { 4920 case MotionEvent.ACTION_DOWN: 4921 mShadeLog.logMotionEvent(event, "onTouch: down action"); 4922 startExpandMotion(x, y, false /* startTracking */, mExpandedHeight); 4923 mMinExpandHeight = 0.0f; 4924 mPanelClosedOnDown = isFullyCollapsed(); 4925 mHasLayoutedSinceDown = false; 4926 mUpdateFlingOnLayout = false; 4927 mMotionAborted = false; 4928 mDownTime = mSystemClock.uptimeMillis(); 4929 mTouchAboveFalsingThreshold = false; 4930 mCollapsedAndHeadsUpOnDown = 4931 isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp(); 4932 addMovement(event); 4933 boolean regularHeightAnimationRunning = isShadeOrQsHeightAnimationRunning(); 4934 if (!mGestureWaitForTouchSlop || regularHeightAnimationRunning) { 4935 mTouchSlopExceeded = regularHeightAnimationRunning 4936 || mTouchSlopExceededBeforeDown; 4937 cancelHeightAnimator(); 4938 onTrackingStarted(); 4939 } 4940 if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp() 4941 && !mCentralSurfaces.isBouncerShowing()) { 4942 startOpening(event); 4943 } 4944 break; 4945 4946 case MotionEvent.ACTION_POINTER_UP: 4947 final int upPointer = event.getPointerId(event.getActionIndex()); 4948 if (mTrackingPointer == upPointer) { 4949 // gesture is ongoing, find a new pointer to track 4950 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1; 4951 final float newY = event.getY(newIndex); 4952 final float newX = event.getX(newIndex); 4953 mTrackingPointer = event.getPointerId(newIndex); 4954 mHandlingPointerUp = true; 4955 startExpandMotion(newX, newY, true /* startTracking */, mExpandedHeight); 4956 mHandlingPointerUp = false; 4957 } 4958 break; 4959 case MotionEvent.ACTION_POINTER_DOWN: 4960 mShadeLog.logMotionEventStatusBarState(event, 4961 mStatusBarStateController.getState(), 4962 "handleTouch: pointer down action"); 4963 if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { 4964 mMotionAborted = true; 4965 endMotionEvent(event, x, y, true /* forceCancel */); 4966 return false; 4967 } 4968 break; 4969 case MotionEvent.ACTION_MOVE: 4970 if (isFullyCollapsed()) { 4971 // If panel is fully collapsed, reset haptic effect before adding movement. 4972 mHasVibratedOnOpen = false; 4973 mShadeLog.logHasVibrated(mHasVibratedOnOpen, mExpandedFraction); 4974 } 4975 addMovement(event); 4976 if (!isFullyCollapsed() && !isOnKeyguard()) { 4977 maybeVibrateOnOpening(true /* openingWithTouch */); 4978 } 4979 float h = y - mInitialExpandY; 4980 4981 // If the panel was collapsed when touching, we only need to check for the 4982 // y-component of the gesture, as we have no conflicting horizontal gesture. 4983 if (Math.abs(h) > getTouchSlop(event) 4984 && (Math.abs(h) > Math.abs(x - mInitialExpandX) 4985 || mIgnoreXTouchSlop)) { 4986 mTouchSlopExceeded = true; 4987 if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) { 4988 if (mInitialOffsetOnTouch != 0f) { 4989 startExpandMotion(x, y, false /* startTracking */, mExpandedHeight); 4990 h = 0; 4991 } 4992 cancelHeightAnimator(); 4993 onTrackingStarted(); 4994 } 4995 } 4996 float newHeight = Math.max(0, h + mInitialOffsetOnTouch); 4997 newHeight = Math.max(newHeight, mMinExpandHeight); 4998 if (-h >= getFalsingThreshold()) { 4999 mTouchAboveFalsingThreshold = true; 5000 mUpwardsWhenThresholdReached = isDirectionUpwards(x, y); 5001 } 5002 if ((!mGestureWaitForTouchSlop || mTracking) 5003 && !(mBlockingExpansionForCurrentTouch 5004 || mQsController.isTrackingBlocked())) { 5005 // Count h==0 as part of swipe-up, 5006 // otherwise {@link NotificationStackScrollLayout} 5007 // wrongly enables stack height updates at the start of lockscreen swipe-up 5008 mAmbientState.setSwipingUp(h <= 0); 5009 mShadeHeightLogger.logFunctionCall("ACTION_MOVE"); 5010 setExpandedHeightInternal(newHeight); 5011 } 5012 break; 5013 5014 case MotionEvent.ACTION_UP: 5015 case MotionEvent.ACTION_CANCEL: 5016 mShadeLog.logMotionEvent(event, "onTouch: up/cancel action"); 5017 addMovement(event); 5018 endMotionEvent(event, x, y, false /* forceCancel */); 5019 // mHeightAnimator is null, there is no remaining frame, ends instrumenting. 5020 if (mHeightAnimator == null) { 5021 if (event.getActionMasked() == MotionEvent.ACTION_UP) { 5022 mQsController.endJankMonitoring(); 5023 } else { 5024 mQsController.cancelJankMonitoring(); 5025 } 5026 } 5027 break; 5028 } 5029 return !mGestureWaitForTouchSlop || mTracking; 5030 } 5031 } 5032 5033 static class SplitShadeTransitionAdapter extends Transition { 5034 private static final String PROP_BOUNDS = "splitShadeTransitionAdapter:bounds"; 5035 private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS }; 5036 5037 private final KeyguardStatusViewController mController; 5038 5039 SplitShadeTransitionAdapter(KeyguardStatusViewController controller) { 5040 mController = controller; 5041 } 5042 5043 private void captureValues(TransitionValues transitionValues) { 5044 Rect boundsRect = new Rect(); 5045 boundsRect.left = transitionValues.view.getLeft(); 5046 boundsRect.top = transitionValues.view.getTop(); 5047 boundsRect.right = transitionValues.view.getRight(); 5048 boundsRect.bottom = transitionValues.view.getBottom(); 5049 transitionValues.values.put(PROP_BOUNDS, boundsRect); 5050 } 5051 5052 @Override 5053 public void captureEndValues(TransitionValues transitionValues) { 5054 captureValues(transitionValues); 5055 } 5056 5057 @Override 5058 public void captureStartValues(TransitionValues transitionValues) { 5059 captureValues(transitionValues); 5060 } 5061 5062 @Nullable 5063 @Override 5064 public Animator createAnimator(ViewGroup sceneRoot, @Nullable TransitionValues startValues, 5065 @Nullable TransitionValues endValues) { 5066 if (startValues == null || endValues == null) { 5067 return null; 5068 } 5069 ValueAnimator anim = ValueAnimator.ofFloat(0, 1); 5070 5071 Rect from = (Rect) startValues.values.get(PROP_BOUNDS); 5072 Rect to = (Rect) endValues.values.get(PROP_BOUNDS); 5073 5074 anim.addUpdateListener(animation -> { 5075 ClockAnimations clockAnims = mController.getClockAnimations(); 5076 if (clockAnims == null) { 5077 return; 5078 } 5079 5080 clockAnims.onPositionUpdated(from, to, animation.getAnimatedFraction()); 5081 }); 5082 5083 return anim; 5084 } 5085 5086 @Override 5087 public String[] getTransitionProperties() { 5088 return TRANSITION_PROPERTIES; 5089 } 5090 } 5091 5092 private final class ShadeAccessibilityDelegate extends AccessibilityDelegate { 5093 @Override 5094 public void onInitializeAccessibilityNodeInfo(View host, 5095 AccessibilityNodeInfo info) { 5096 super.onInitializeAccessibilityNodeInfo(host, info); 5097 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); 5098 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP); 5099 } 5100 5101 @Override 5102 public boolean performAccessibilityAction(View host, int action, Bundle args) { 5103 if (action 5104 == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId() 5105 || action 5106 == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId()) { 5107 mStatusBarKeyguardViewManager.showPrimaryBouncer(true); 5108 return true; 5109 } 5110 return super.performAccessibilityAction(host, action, args); 5111 } 5112 } 5113 5114 /** Listens for when touch tracking begins. */ 5115 interface TrackingStartedListener { 5116 void onTrackingStarted(); 5117 } 5118 5119 /** Listens for when shade begins opening of finishes closing. */ 5120 interface OpenCloseListener { 5121 /** Called when the shade finishes closing. */ 5122 void onClosingFinished(); 5123 /** Called when the shade starts opening. */ 5124 void onOpenStarted(); 5125 } 5126 } 5127