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