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