1 /* 2 * Copyright (C) 2014 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.statusbar.phone; 18 19 import static android.view.WindowInsets.Type.navigationBars; 20 21 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN; 22 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction; 23 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK; 24 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; 25 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; 26 import static com.android.systemui.util.kotlin.JavaAdapterKt.combineFlows; 27 28 import android.content.Context; 29 import android.content.res.ColorStateList; 30 import android.hardware.biometrics.BiometricSourceType; 31 import android.os.Bundle; 32 import android.os.SystemClock; 33 import android.os.Trace; 34 import android.util.Log; 35 import android.view.KeyEvent; 36 import android.view.MotionEvent; 37 import android.view.View; 38 import android.view.ViewGroup; 39 import android.view.ViewRootImpl; 40 import android.window.BackEvent; 41 import android.window.OnBackAnimationCallback; 42 import android.window.OnBackInvokedDispatcher; 43 44 import androidx.annotation.NonNull; 45 import androidx.annotation.Nullable; 46 import androidx.annotation.VisibleForTesting; 47 48 import com.android.internal.util.LatencyTracker; 49 import com.android.internal.widget.LockPatternUtils; 50 import com.android.keyguard.AuthKeyguardMessageArea; 51 import com.android.keyguard.KeyguardMessageAreaController; 52 import com.android.keyguard.KeyguardSecurityModel; 53 import com.android.keyguard.KeyguardUpdateMonitor; 54 import com.android.keyguard.KeyguardUpdateMonitorCallback; 55 import com.android.keyguard.KeyguardViewController; 56 import com.android.keyguard.TrustGrantFlags; 57 import com.android.keyguard.ViewMediatorCallback; 58 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor; 59 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; 60 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor; 61 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback; 62 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor; 63 import com.android.systemui.bouncer.ui.BouncerView; 64 import com.android.systemui.dagger.SysUISingleton; 65 import com.android.systemui.dagger.qualifiers.Main; 66 import com.android.systemui.dock.DockManager; 67 import com.android.systemui.dreams.DreamOverlayStateController; 68 import com.android.systemui.flags.FeatureFlags; 69 import com.android.systemui.flags.Flags; 70 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; 71 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; 72 import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor; 73 import com.android.systemui.navigationbar.NavigationBarView; 74 import com.android.systemui.navigationbar.NavigationModeController; 75 import com.android.systemui.navigationbar.TaskbarDelegate; 76 import com.android.systemui.plugins.ActivityStarter; 77 import com.android.systemui.plugins.statusbar.StatusBarStateController; 78 import com.android.systemui.shade.ShadeController; 79 import com.android.systemui.shade.ShadeExpansionChangeEvent; 80 import com.android.systemui.shade.ShadeExpansionListener; 81 import com.android.systemui.shade.ShadeExpansionStateManager; 82 import com.android.systemui.shade.ShadeViewController; 83 import com.android.systemui.shared.system.QuickStepContract; 84 import com.android.systemui.shared.system.SysUiStatsLog; 85 import com.android.systemui.statusbar.NotificationMediaManager; 86 import com.android.systemui.statusbar.NotificationShadeWindowController; 87 import com.android.systemui.statusbar.RemoteInputController; 88 import com.android.systemui.statusbar.StatusBarState; 89 import com.android.systemui.statusbar.SysuiStatusBarStateController; 90 import com.android.systemui.statusbar.policy.ConfigurationController; 91 import com.android.systemui.statusbar.policy.KeyguardStateController; 92 import com.android.systemui.unfold.FoldAodAnimationController; 93 import com.android.systemui.unfold.SysUIUnfoldComponent; 94 95 import dagger.Lazy; 96 97 import java.io.PrintWriter; 98 import java.util.ArrayList; 99 import java.util.HashSet; 100 import java.util.Objects; 101 import java.util.Optional; 102 import java.util.Set; 103 104 import javax.inject.Inject; 105 106 import kotlinx.coroutines.CoroutineDispatcher; 107 108 /** 109 * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back 110 * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, 111 * which is in turn, reported to this class by the current 112 * {@link com.android.keyguard.KeyguardViewController}. 113 */ 114 @SysUISingleton 115 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback, 116 StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener, 117 ShadeExpansionListener, NavigationModeController.ModeChangedListener, 118 KeyguardViewController, FoldAodAnimationController.FoldAodAnimationStatus { 119 120 // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. 121 private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3; 122 123 // Delay for showing the navigation bar when the bouncer appears. This should be kept in sync 124 // with the appear animations of the PIN/pattern/password views. 125 private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320; 126 127 // The duration to fade the nav bar content in/out when the device starts to sleep 128 private static final long NAV_BAR_CONTENT_FADE_DURATION = 125; 129 130 // Duration of the Keyguard dismissal animation in case the user is currently locked. This is to 131 // make everything a bit slower to bridge a gap until the user is unlocked and home screen has 132 // dranw its first frame. 133 private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000; 134 135 private static String TAG = "StatusBarKeyguardViewManager"; 136 private static final boolean DEBUG = false; 137 138 protected final Context mContext; 139 private final ConfigurationController mConfigurationController; 140 private final NavigationModeController mNavigationModeController; 141 private final NotificationShadeWindowController mNotificationShadeWindowController; 142 private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory; 143 private final DreamOverlayStateController mDreamOverlayStateController; 144 @Nullable 145 private final FoldAodAnimationController mFoldAodAnimationController; 146 KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController; 147 private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor; 148 private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; 149 private final AlternateBouncerInteractor mAlternateBouncerInteractor; 150 private final BouncerView mPrimaryBouncerView; 151 private final Lazy<ShadeController> mShadeController; 152 153 // Local cache of expansion events, to avoid duplicates 154 private float mFraction = -1f; 155 private boolean mTracking = false; 156 private boolean mBouncerShowingOverDream; 157 158 private final PrimaryBouncerExpansionCallback mExpansionCallback = 159 new PrimaryBouncerExpansionCallback() { 160 private boolean mPrimaryBouncerAnimating; 161 162 @Override 163 public void onFullyShown() { 164 mPrimaryBouncerAnimating = false; 165 updateStates(); 166 } 167 168 @Override 169 public void onStartingToHide() { 170 mPrimaryBouncerAnimating = true; 171 updateStates(); 172 } 173 174 @Override 175 public void onStartingToShow() { 176 mPrimaryBouncerAnimating = true; 177 updateStates(); 178 } 179 180 @Override 181 public void onFullyHidden() { 182 mPrimaryBouncerAnimating = false; 183 updateStates(); 184 } 185 186 @Override 187 public void onExpansionChanged(float expansion) { 188 if (mPrimaryBouncerAnimating) { 189 mCentralSurfaces.setPrimaryBouncerHiddenFraction(expansion); 190 } 191 } 192 193 @Override 194 public void onVisibilityChanged(boolean isVisible) { 195 mBouncerShowingOverDream = 196 isVisible && mDreamOverlayStateController.isOverlayActive(); 197 198 if (!isVisible) { 199 mCentralSurfaces.setPrimaryBouncerHiddenFraction(EXPANSION_HIDDEN); 200 } 201 202 /* Register predictive back callback when keyguard becomes visible, and unregister 203 when it's hidden. */ 204 if (isVisible) { 205 registerBackCallback(); 206 } else { 207 unregisterBackCallback(); 208 } 209 } 210 }; 211 212 private final OnBackAnimationCallback mOnBackInvokedCallback = new OnBackAnimationCallback() { 213 @Override 214 public void onBackInvoked() { 215 if (DEBUG) { 216 Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()"); 217 } 218 onBackPressed(); 219 if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) { 220 mPrimaryBouncerView.getDelegate().getBackCallback().onBackInvoked(); 221 } 222 } 223 224 @Override 225 public void onBackProgressed(BackEvent event) { 226 if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) { 227 mPrimaryBouncerView.getDelegate().getBackCallback().onBackProgressed(event); 228 } 229 } 230 231 @Override 232 public void onBackCancelled() { 233 if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) { 234 mPrimaryBouncerView.getDelegate().getBackCallback().onBackCancelled(); 235 } 236 } 237 238 @Override 239 public void onBackStarted(BackEvent event) { 240 if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) { 241 mPrimaryBouncerView.getDelegate().getBackCallback().onBackStarted(event); 242 } 243 } 244 }; 245 private boolean mIsBackCallbackRegistered = false; 246 247 private final DockManager.DockEventListener mDockEventListener = 248 new DockManager.DockEventListener() { 249 @Override 250 public void onEvent(int event) { 251 boolean isDocked = mDockManager.isDocked(); 252 if (isDocked == mIsDocked) { 253 return; 254 } 255 mIsDocked = isDocked; 256 updateStates(); 257 } 258 }; 259 260 protected LockPatternUtils mLockPatternUtils; 261 protected ViewMediatorCallback mViewMediatorCallback; 262 @Nullable protected CentralSurfaces mCentralSurfaces; 263 private ShadeViewController mShadeViewController; 264 private BiometricUnlockController mBiometricUnlockController; 265 private boolean mCentralSurfacesRegistered; 266 267 private View mNotificationContainer; 268 269 protected boolean mRemoteInputActive; 270 private boolean mGlobalActionsVisible = false; 271 private boolean mLastGlobalActionsVisible = false; 272 private boolean mDozing; 273 private boolean mPulsing; 274 private boolean mGesturalNav; 275 private boolean mIsDocked; 276 private boolean mScreenOffAnimationPlaying; 277 278 protected boolean mFirstUpdate = true; 279 protected boolean mLastShowing; 280 protected boolean mLastOccluded; 281 private boolean mLastPrimaryBouncerShowing; 282 private boolean mLastPrimaryBouncerIsOrWillBeShowing; 283 private boolean mLastBouncerDismissible; 284 protected boolean mLastRemoteInputActive; 285 private boolean mLastDozing; 286 private boolean mLastGesturalNav; 287 private boolean mLastIsDocked; 288 private boolean mLastPulsing; 289 private int mLastBiometricMode; 290 private boolean mLastScreenOffAnimationPlaying; 291 private float mQsExpansion; 292 293 private FeatureFlags mFlags; 294 295 final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>(); 296 private boolean mIsBackAnimationEnabled; 297 private final boolean mUdfpsNewTouchDetectionEnabled; 298 private final UdfpsOverlayInteractor mUdfpsOverlayInteractor; 299 private final ActivityStarter mActivityStarter; 300 301 private OnDismissAction mAfterKeyguardGoneAction; 302 private Runnable mKeyguardGoneCancelAction; 303 private boolean mDismissActionWillAnimateOnKeyguard; 304 private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>(); 305 306 // Dismiss action to be launched when we stop dozing or the keyguard is gone. 307 private DismissWithActionRequest mPendingWakeupAction; 308 private final KeyguardStateController mKeyguardStateController; 309 private final NotificationMediaManager mMediaManager; 310 private final SysuiStatusBarStateController mStatusBarStateController; 311 private final DockManager mDockManager; 312 private final KeyguardUpdateMonitor mKeyguardUpdateManager; 313 private final LatencyTracker mLatencyTracker; 314 private final KeyguardSecurityModel mKeyguardSecurityModel; 315 @Nullable private KeyguardBypassController mBypassController; 316 @Nullable private OccludingAppBiometricUI mOccludingAppBiometricUI; 317 318 @Nullable private TaskbarDelegate mTaskbarDelegate; 319 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = 320 new KeyguardUpdateMonitorCallback() { 321 @Override 322 public void onTrustGrantedForCurrentUser( 323 boolean dismissKeyguard, 324 boolean newlyUnlocked, 325 @NonNull TrustGrantFlags flags, 326 @Nullable String message 327 ) { 328 updateAlternateBouncerShowing(mAlternateBouncerInteractor.maybeHide()); 329 } 330 331 @Override 332 public void onEmergencyCallAction() { 333 // Since we won't get a setOccluded call we have to reset the view manually such that 334 // the bouncer goes away. 335 if (mKeyguardStateController.isOccluded()) { 336 reset(true /* hideBouncerWhenShowing */); 337 } 338 } 339 }; 340 private Lazy<WindowManagerLockscreenVisibilityInteractor> mWmLockscreenVisibilityInteractor; 341 342 @Inject StatusBarKeyguardViewManager( Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils, SysuiStatusBarStateController sysuiStatusBarStateController, ConfigurationController configurationController, KeyguardUpdateMonitor keyguardUpdateMonitor, DreamOverlayStateController dreamOverlayStateController, NavigationModeController navigationModeController, DockManager dockManager, NotificationShadeWindowController notificationShadeWindowController, KeyguardStateController keyguardStateController, NotificationMediaManager notificationMediaManager, KeyguardMessageAreaController.Factory keyguardMessageAreaFactory, Optional<SysUIUnfoldComponent> sysUIUnfoldComponent, Lazy<ShadeController> shadeController, LatencyTracker latencyTracker, KeyguardSecurityModel keyguardSecurityModel, FeatureFlags featureFlags, PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor, PrimaryBouncerInteractor primaryBouncerInteractor, BouncerView primaryBouncerView, AlternateBouncerInteractor alternateBouncerInteractor, UdfpsOverlayInteractor udfpsOverlayInteractor, ActivityStarter activityStarter, KeyguardTransitionInteractor keyguardTransitionInteractor, @Main CoroutineDispatcher mainDispatcher, Lazy<WindowManagerLockscreenVisibilityInteractor> wmLockscreenVisibilityInteractor )343 public StatusBarKeyguardViewManager( 344 Context context, 345 ViewMediatorCallback callback, 346 LockPatternUtils lockPatternUtils, 347 SysuiStatusBarStateController sysuiStatusBarStateController, 348 ConfigurationController configurationController, 349 KeyguardUpdateMonitor keyguardUpdateMonitor, 350 DreamOverlayStateController dreamOverlayStateController, 351 NavigationModeController navigationModeController, 352 DockManager dockManager, 353 NotificationShadeWindowController notificationShadeWindowController, 354 KeyguardStateController keyguardStateController, 355 NotificationMediaManager notificationMediaManager, 356 KeyguardMessageAreaController.Factory keyguardMessageAreaFactory, 357 Optional<SysUIUnfoldComponent> sysUIUnfoldComponent, 358 Lazy<ShadeController> shadeController, 359 LatencyTracker latencyTracker, 360 KeyguardSecurityModel keyguardSecurityModel, 361 FeatureFlags featureFlags, 362 PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor, 363 PrimaryBouncerInteractor primaryBouncerInteractor, 364 BouncerView primaryBouncerView, 365 AlternateBouncerInteractor alternateBouncerInteractor, 366 UdfpsOverlayInteractor udfpsOverlayInteractor, 367 ActivityStarter activityStarter, 368 KeyguardTransitionInteractor keyguardTransitionInteractor, 369 @Main CoroutineDispatcher mainDispatcher, 370 Lazy<WindowManagerLockscreenVisibilityInteractor> wmLockscreenVisibilityInteractor 371 ) { 372 mContext = context; 373 mViewMediatorCallback = callback; 374 mLockPatternUtils = lockPatternUtils; 375 mConfigurationController = configurationController; 376 mNavigationModeController = navigationModeController; 377 mNotificationShadeWindowController = notificationShadeWindowController; 378 mDreamOverlayStateController = dreamOverlayStateController; 379 mKeyguardStateController = keyguardStateController; 380 mMediaManager = notificationMediaManager; 381 mKeyguardUpdateManager = keyguardUpdateMonitor; 382 mStatusBarStateController = sysuiStatusBarStateController; 383 mDockManager = dockManager; 384 mKeyguardMessageAreaFactory = keyguardMessageAreaFactory; 385 mShadeController = shadeController; 386 mLatencyTracker = latencyTracker; 387 mKeyguardSecurityModel = keyguardSecurityModel; 388 mFlags = featureFlags; 389 mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor; 390 mPrimaryBouncerInteractor = primaryBouncerInteractor; 391 mPrimaryBouncerView = primaryBouncerView; 392 mFoldAodAnimationController = sysUIUnfoldComponent 393 .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null); 394 mAlternateBouncerInteractor = alternateBouncerInteractor; 395 mIsBackAnimationEnabled = 396 featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM); 397 mUdfpsNewTouchDetectionEnabled = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION); 398 mUdfpsOverlayInteractor = udfpsOverlayInteractor; 399 mActivityStarter = activityStarter; 400 mKeyguardTransitionInteractor = keyguardTransitionInteractor; 401 mMainDispatcher = mainDispatcher; 402 mWmLockscreenVisibilityInteractor = wmLockscreenVisibilityInteractor; 403 } 404 405 KeyguardTransitionInteractor mKeyguardTransitionInteractor; 406 CoroutineDispatcher mMainDispatcher; 407 408 @Override registerCentralSurfaces(CentralSurfaces centralSurfaces, ShadeViewController shadeViewController, ShadeExpansionStateManager shadeExpansionStateManager, BiometricUnlockController biometricUnlockController, View notificationContainer, KeyguardBypassController bypassController)409 public void registerCentralSurfaces(CentralSurfaces centralSurfaces, 410 ShadeViewController shadeViewController, 411 ShadeExpansionStateManager shadeExpansionStateManager, 412 BiometricUnlockController biometricUnlockController, 413 View notificationContainer, 414 KeyguardBypassController bypassController) { 415 mCentralSurfaces = centralSurfaces; 416 mBiometricUnlockController = biometricUnlockController; 417 418 mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback); 419 mShadeViewController = shadeViewController; 420 if (shadeExpansionStateManager != null) { 421 ShadeExpansionChangeEvent currentState = 422 shadeExpansionStateManager.addExpansionListener(this); 423 onPanelExpansionChanged(currentState); 424 } 425 mBypassController = bypassController; 426 mNotificationContainer = notificationContainer; 427 mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create( 428 centralSurfaces.getKeyguardMessageArea()); 429 mCentralSurfacesRegistered = true; 430 431 registerListeners(); 432 } 433 434 435 /** 436 * Sets the given OccludingAppBiometricUI to null if it's the current auth interceptor. Else, 437 * does nothing. 438 */ removeOccludingAppBiometricUI(@onNull OccludingAppBiometricUI biometricUI)439 public void removeOccludingAppBiometricUI(@NonNull OccludingAppBiometricUI biometricUI) { 440 if (Objects.equals(mOccludingAppBiometricUI, biometricUI)) { 441 mOccludingAppBiometricUI = null; 442 } 443 } 444 445 /** 446 * Sets a new OccludingAppBiometricUI. 447 */ setOccludingAppBiometricUI(@onNull OccludingAppBiometricUI biometricUI)448 public void setOccludingAppBiometricUI(@NonNull OccludingAppBiometricUI biometricUI) { 449 if (!Objects.equals(mOccludingAppBiometricUI, biometricUI)) { 450 mOccludingAppBiometricUI = biometricUI; 451 } 452 } 453 registerListeners()454 private void registerListeners() { 455 mKeyguardUpdateManager.registerCallback(mUpdateMonitorCallback); 456 mStatusBarStateController.addCallback(this); 457 mConfigurationController.addCallback(this); 458 mGesturalNav = QuickStepContract.isGesturalMode( 459 mNavigationModeController.addListener(this)); 460 if (mFoldAodAnimationController != null) { 461 mFoldAodAnimationController.addCallback(this); 462 } 463 if (mDockManager != null) { 464 mDockManager.addListener(mDockEventListener); 465 mIsDocked = mDockManager.isDocked(); 466 } 467 468 if (mFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) { 469 mShadeViewController.postToView(() -> 470 collectFlow( 471 getViewRootImpl().getView(), 472 combineFlows( 473 mKeyguardTransitionInteractor.getFinishedKeyguardState(), 474 mWmLockscreenVisibilityInteractor.get() 475 .getUsingKeyguardGoingAwayAnimation(), 476 (finishedState, animating) -> 477 KeyguardInteractor.Companion.isKeyguardVisibleInState( 478 finishedState) 479 || animating), 480 this::consumeShowStatusBarKeyguardView)); 481 } 482 } 483 consumeShowStatusBarKeyguardView(boolean show)484 private void consumeShowStatusBarKeyguardView(boolean show) { 485 if (show != mLastShowing) { 486 if (show) { 487 show(null); 488 } else { 489 hide(0, 0); 490 } 491 } 492 } 493 494 /** Register a callback, to be invoked by the Predictive Back system. */ registerBackCallback()495 private void registerBackCallback() { 496 if (!mIsBackCallbackRegistered) { 497 ViewRootImpl viewRoot = getViewRootImpl(); 498 if (viewRoot != null) { 499 viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback( 500 OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback); 501 mIsBackCallbackRegistered = true; 502 } else { 503 if (DEBUG) { 504 Log.d(TAG, "view root was null, could not register back callback"); 505 } 506 } 507 } else { 508 if (DEBUG) { 509 Log.d(TAG, "prevented registering back callback twice"); 510 } 511 } 512 } 513 514 /** Unregister the callback formerly registered with the Predictive Back system. */ unregisterBackCallback()515 private void unregisterBackCallback() { 516 if (mIsBackCallbackRegistered) { 517 ViewRootImpl viewRoot = getViewRootImpl(); 518 if (viewRoot != null) { 519 viewRoot.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback( 520 mOnBackInvokedCallback); 521 mIsBackCallbackRegistered = false; 522 } else { 523 if (DEBUG) { 524 Log.d(TAG, "view root was null, could not unregister back callback"); 525 } 526 } 527 } else { 528 if (DEBUG) { 529 Log.d(TAG, "prevented unregistering back callback twice"); 530 } 531 } 532 } 533 shouldPlayBackAnimation()534 private boolean shouldPlayBackAnimation() { 535 // Suppress back animation when bouncer shouldn't be dismissed on back invocation. 536 return !needsFullscreenBouncer() && mIsBackAnimationEnabled; 537 } 538 539 @Override onDensityOrFontScaleChanged()540 public void onDensityOrFontScaleChanged() { 541 hideBouncer(true /* destroyView */); 542 } 543 beginShowingBouncer(ShadeExpansionChangeEvent event)544 private boolean beginShowingBouncer(ShadeExpansionChangeEvent event) { 545 // Avoid having the shade and the bouncer open at the same time over a dream. 546 final boolean hideBouncerOverDream = 547 mDreamOverlayStateController.isOverlayActive() 548 && (mShadeViewController.isExpanded() 549 || mShadeViewController.isExpandingOrCollapsing()); 550 551 final boolean isUserTrackingStarted = 552 event.getFraction() != EXPANSION_HIDDEN && event.getTracking(); 553 554 return mKeyguardStateController.isShowing() 555 && !primaryBouncerIsOrWillBeShowing() 556 && !mKeyguardStateController.isKeyguardGoingAway() 557 && isUserTrackingStarted 558 && !hideBouncerOverDream 559 && !mKeyguardStateController.isOccluded() 560 && !mKeyguardStateController.canDismissLockScreen() 561 && !bouncerIsAnimatingAway() 562 && !mShadeViewController.isUnlockHintRunning() 563 && !(mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED); 564 } 565 566 @Override onPanelExpansionChanged(ShadeExpansionChangeEvent event)567 public void onPanelExpansionChanged(ShadeExpansionChangeEvent event) { 568 float fraction = event.getFraction(); 569 boolean tracking = event.getTracking(); 570 571 if (mFraction == fraction && mTracking == tracking) { 572 // Ignore duplicate events, as they will cause confusion with bouncer expansion 573 return; 574 } 575 mFraction = fraction; 576 mTracking = tracking; 577 578 /* 579 * The bouncer may have received a call to show(), or the following will infer it from 580 * device state and touch handling. The bouncer MUST have been notified that it is about to 581 * show if any subsequent events are to be handled. 582 */ 583 if (beginShowingBouncer(event)) { 584 mPrimaryBouncerInteractor.show(/* isScrimmed= */false); 585 } 586 587 if (!primaryBouncerIsOrWillBeShowing()) { 588 return; 589 } 590 591 if (mKeyguardStateController.isShowing()) { 592 mPrimaryBouncerInteractor.setPanelExpansion(fraction); 593 } else { 594 mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN); 595 } 596 } 597 598 /** 599 * Update the global actions visibility state in order to show the navBar when active. 600 */ setGlobalActionsVisible(boolean isVisible)601 public void setGlobalActionsVisible(boolean isVisible) { 602 mGlobalActionsVisible = isVisible; 603 updateStates(); 604 } 605 setTaskbarDelegate(TaskbarDelegate taskbarDelegate)606 public void setTaskbarDelegate(TaskbarDelegate taskbarDelegate) { 607 mTaskbarDelegate = taskbarDelegate; 608 } 609 610 /** 611 * Show the keyguard. Will handle creating and attaching to the view manager 612 * lazily. 613 */ 614 @Override show(Bundle options)615 public void show(Bundle options) { 616 Trace.beginSection("StatusBarKeyguardViewManager#show"); 617 mNotificationShadeWindowController.setKeyguardShowing(true); 618 mKeyguardStateController.notifyKeyguardState(true, 619 mKeyguardStateController.isOccluded()); 620 reset(true /* hideBouncerWhenShowing */); 621 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 622 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); 623 Trace.endSection(); 624 } 625 626 /** 627 * Shows the notification keyguard or the bouncer depending on 628 * {@link #needsFullscreenBouncer()}. 629 */ showBouncerOrKeyguard(boolean hideBouncerWhenShowing)630 protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) { 631 if (needsFullscreenBouncer() && !mDozing) { 632 // The keyguard might be showing (already). So we need to hide it. 633 mCentralSurfaces.hideKeyguard(); 634 mPrimaryBouncerInteractor.show(true); 635 } else { 636 mCentralSurfaces.showKeyguard(); 637 if (hideBouncerWhenShowing) { 638 hideBouncer(false /* destroyView */); 639 } 640 } 641 updateStates(); 642 } 643 644 /** 645 * 646 * If possible, shows the alternate bouncer. Else, shows the primary (pin/pattern/password) 647 * bouncer. 648 * @param scrimmed true when the primary bouncer should show scrimmed, 649 * false when the user will be dragging it and translation should be deferred 650 * {@see KeyguardBouncer#show(boolean, boolean)} 651 */ showBouncer(boolean scrimmed)652 public void showBouncer(boolean scrimmed) { 653 if (!mAlternateBouncerInteractor.show()) { 654 showPrimaryBouncer(scrimmed); 655 } else { 656 updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState()); 657 } 658 } 659 660 /** 661 * Hides the input bouncer (pin/password/pattern). 662 */ 663 @VisibleForTesting hideBouncer(boolean destroyView)664 void hideBouncer(boolean destroyView) { 665 mPrimaryBouncerInteractor.hide(); 666 if (mKeyguardStateController.isShowing()) { 667 // If we were showing the bouncer and then aborting, we need to also clear out any 668 // potential actions unless we actually unlocked. 669 cancelPostAuthActions(); 670 } 671 cancelPendingWakeupAction(); 672 } 673 674 /** 675 * Shows the primary bouncer - the pin/pattern/password challenge on the lock screen. 676 * 677 * @param scrimmed true when the bouncer should show scrimmed, false when the user will be 678 * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)} 679 */ showPrimaryBouncer(boolean scrimmed)680 public void showPrimaryBouncer(boolean scrimmed) { 681 hideAlternateBouncer(false); 682 if (mKeyguardStateController.isShowing() && !isBouncerShowing()) { 683 mPrimaryBouncerInteractor.show(scrimmed); 684 } 685 updateStates(); 686 } 687 dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone)688 public void dismissWithAction(OnDismissAction r, Runnable cancelAction, 689 boolean afterKeyguardGone) { 690 dismissWithAction(r, cancelAction, afterKeyguardGone, null /* message */); 691 } 692 dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone, String message)693 public void dismissWithAction(OnDismissAction r, Runnable cancelAction, 694 boolean afterKeyguardGone, String message) { 695 if (mKeyguardStateController.isShowing()) { 696 try { 697 Trace.beginSection("StatusBarKeyguardViewManager#dismissWithAction"); 698 cancelPendingWakeupAction(); 699 // If we're dozing, this needs to be delayed until after we wake up - unless we're 700 // wake-and-unlocking, because there dozing will last until the end of the 701 // transition. 702 if (mDozing && !isWakeAndUnlocking()) { 703 mPendingWakeupAction = new DismissWithActionRequest( 704 r, cancelAction, afterKeyguardGone, message); 705 return; 706 } 707 708 mAfterKeyguardGoneAction = r; 709 mKeyguardGoneCancelAction = cancelAction; 710 mDismissActionWillAnimateOnKeyguard = r != null && r.willRunAnimationOnKeyguard(); 711 712 // If there is an alternate auth interceptor (like the UDFPS), show that one 713 // instead of the bouncer. 714 if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) { 715 if (!afterKeyguardGone) { 716 mPrimaryBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction, 717 mKeyguardGoneCancelAction); 718 mAfterKeyguardGoneAction = null; 719 mKeyguardGoneCancelAction = null; 720 } 721 722 updateAlternateBouncerShowing(mAlternateBouncerInteractor.show()); 723 setKeyguardMessage(message, null); 724 return; 725 } 726 727 mViewMediatorCallback.setCustomMessage(message); 728 if (afterKeyguardGone) { 729 // we'll handle the dismiss action after keyguard is gone, so just show the 730 // bouncer 731 mPrimaryBouncerInteractor.show(/* isScrimmed= */true); 732 } else { 733 // after authentication success, run dismiss action with the option to defer 734 // hiding the keyguard based on the return value of the OnDismissAction 735 mPrimaryBouncerInteractor.setDismissAction( 736 mAfterKeyguardGoneAction, mKeyguardGoneCancelAction); 737 mPrimaryBouncerInteractor.show(/* isScrimmed= */true); 738 // bouncer will handle the dismiss action, so we no longer need to track it here 739 mAfterKeyguardGoneAction = null; 740 mKeyguardGoneCancelAction = null; 741 } 742 } finally { 743 Trace.endSection(); 744 } 745 } 746 updateStates(); 747 } 748 isWakeAndUnlocking()749 private boolean isWakeAndUnlocking() { 750 int mode = mBiometricUnlockController.getMode(); 751 return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING; 752 } 753 754 /** 755 * Adds a {@param runnable} to be executed after Keyguard is gone. 756 */ addAfterKeyguardGoneRunnable(Runnable runnable)757 public void addAfterKeyguardGoneRunnable(Runnable runnable) { 758 mAfterKeyguardGoneRunnables.add(runnable); 759 } 760 761 @Override reset(boolean hideBouncerWhenShowing)762 public void reset(boolean hideBouncerWhenShowing) { 763 if (mKeyguardStateController.isShowing() && !bouncerIsAnimatingAway()) { 764 final boolean isOccluded = mKeyguardStateController.isOccluded(); 765 // Hide quick settings. 766 mShadeViewController.resetViews(/* animate= */ !isOccluded); 767 // Hide bouncer and quick-quick settings. 768 if (isOccluded && !mDozing) { 769 mCentralSurfaces.hideKeyguard(); 770 if (hideBouncerWhenShowing || needsFullscreenBouncer()) { 771 hideBouncer(false /* destroyView */); 772 } 773 } else { 774 showBouncerOrKeyguard(hideBouncerWhenShowing); 775 } 776 if (hideBouncerWhenShowing) { 777 hideAlternateBouncer(true); 778 } 779 mKeyguardUpdateManager.sendKeyguardReset(); 780 updateStates(); 781 } 782 } 783 784 @Override hideAlternateBouncer(boolean updateScrim)785 public void hideAlternateBouncer(boolean updateScrim) { 786 updateAlternateBouncerShowing(mAlternateBouncerInteractor.hide() && updateScrim); 787 } 788 updateAlternateBouncerShowing(boolean updateScrim)789 private void updateAlternateBouncerShowing(boolean updateScrim) { 790 if (!mCentralSurfacesRegistered) { 791 // if CentralSurfaces hasn't been registered yet, then the controllers below haven't 792 // been initialized yet so there's no need to attempt to forward them events. 793 return; 794 } 795 796 final boolean isShowingAlternateBouncer = mAlternateBouncerInteractor.isVisibleState(); 797 if (mKeyguardMessageAreaController != null) { 798 mKeyguardMessageAreaController.setIsVisible(isShowingAlternateBouncer); 799 mKeyguardMessageAreaController.setMessage(""); 800 } 801 mBypassController.setAltBouncerShowing(isShowingAlternateBouncer); 802 mKeyguardUpdateManager.setAlternateBouncerShowing(isShowingAlternateBouncer); 803 804 if (updateScrim) { 805 mCentralSurfaces.updateScrimController(); 806 } 807 } 808 809 @Override onStartedWakingUp()810 public void onStartedWakingUp() { 811 mNotificationShadeWindowController.getWindowRootView().getWindowInsetsController() 812 .setAnimationsDisabled(false); 813 NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView(); 814 if (navBarView != null) { 815 navBarView.forEachView(view -> 816 view.animate() 817 .alpha(1f) 818 .setDuration(NAV_BAR_CONTENT_FADE_DURATION) 819 .start()); 820 } 821 } 822 823 @Override onStartedGoingToSleep()824 public void onStartedGoingToSleep() { 825 mNotificationShadeWindowController.getWindowRootView().getWindowInsetsController() 826 .setAnimationsDisabled(true); 827 NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView(); 828 if (navBarView != null) { 829 navBarView.forEachView(view -> 830 view.animate() 831 .alpha(0f) 832 .setDuration(NAV_BAR_CONTENT_FADE_DURATION) 833 .start()); 834 } 835 } 836 837 @Override onFinishedGoingToSleep()838 public void onFinishedGoingToSleep() { 839 mPrimaryBouncerInteractor.hide(); 840 } 841 842 @Override onRemoteInputActive(boolean active)843 public void onRemoteInputActive(boolean active) { 844 mRemoteInputActive = active; 845 updateStates(); 846 } 847 setDozing(boolean dozing)848 private void setDozing(boolean dozing) { 849 if (mDozing != dozing) { 850 mDozing = dozing; 851 if (dozing || needsFullscreenBouncer() 852 || mKeyguardStateController.isOccluded()) { 853 reset(dozing /* hideBouncerWhenShowing */); 854 } 855 updateStates(); 856 857 if (!dozing) { 858 launchPendingWakeupAction(); 859 } 860 } 861 } 862 863 /** 864 * If {@link CentralSurfaces} is pulsing. 865 */ setPulsing(boolean pulsing)866 public void setPulsing(boolean pulsing) { 867 if (mPulsing != pulsing) { 868 mPulsing = pulsing; 869 updateStates(); 870 } 871 } 872 873 @Override setNeedsInput(boolean needsInput)874 public void setNeedsInput(boolean needsInput) { 875 mNotificationShadeWindowController.setKeyguardNeedsInput(needsInput); 876 } 877 878 @Override isUnlockWithWallpaper()879 public boolean isUnlockWithWallpaper() { 880 return mNotificationShadeWindowController.isShowingWallpaper(); 881 } 882 883 @Override isBouncerShowingOverDream()884 public boolean isBouncerShowingOverDream() { 885 return mBouncerShowingOverDream; 886 } 887 888 @Override setOccluded(boolean occluded, boolean animate)889 public void setOccluded(boolean occluded, boolean animate) { 890 final boolean wasOccluded = mKeyguardStateController.isOccluded(); 891 final boolean isOccluding = !wasOccluded && occluded; 892 final boolean isUnOccluding = wasOccluded && !occluded; 893 mKeyguardStateController.notifyKeyguardState( 894 mKeyguardStateController.isShowing(), occluded); 895 updateStates(); 896 final boolean isShowing = mKeyguardStateController.isShowing(); 897 final boolean isOccluded = mKeyguardStateController.isOccluded(); 898 899 if (isShowing && isOccluding) { 900 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 901 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); 902 if (mCentralSurfaces.isLaunchingActivityOverLockscreen()) { 903 // When isLaunchingActivityOverLockscreen() is true, we know for sure that the post 904 // collapse runnables will be run. 905 mShadeController.get().addPostCollapseAction(() -> { 906 mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); 907 reset(true /* hideBouncerWhenShowing */); 908 }); 909 return; 910 } 911 } else if (isShowing && isUnOccluding) { 912 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 913 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); 914 } 915 if (isShowing) { 916 mMediaManager.updateMediaMetaData(false, animate && !isOccluded); 917 } 918 mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); 919 920 // setDozing(false) will call reset once we stop dozing. Also, if we're going away, there's 921 // no need to reset the keyguard views as we'll be gone shortly. Resetting now could cause 922 // unexpected visible behavior if the keyguard is still visible as we're animating unlocked. 923 if (!mDozing && !mKeyguardStateController.isKeyguardGoingAway()) { 924 // If Keyguard is reshown, don't hide the bouncer as it might just have been requested 925 // by a FLAG_DISMISS_KEYGUARD_ACTIVITY. 926 reset(isOccluding /* hideBouncerWhenShowing*/); 927 } 928 } 929 930 @Override startPreHideAnimation(Runnable finishRunnable)931 public void startPreHideAnimation(Runnable finishRunnable) { 932 if (primaryBouncerIsShowing()) { 933 mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable); 934 mShadeViewController.startBouncerPreHideAnimation(); 935 936 // We update the state (which will show the keyguard) only if an animation will run on 937 // the keyguard. If there is no animation, we wait before updating the state so that we 938 // go directly from bouncer to launcher/app. 939 if (mDismissActionWillAnimateOnKeyguard) { 940 updateStates(); 941 } 942 } else if (finishRunnable != null) { 943 finishRunnable.run(); 944 } 945 mShadeViewController.blockExpansionForCurrentTouch(); 946 } 947 948 @Override blockPanelExpansionFromCurrentTouch()949 public void blockPanelExpansionFromCurrentTouch() { 950 mShadeViewController.blockExpansionForCurrentTouch(); 951 } 952 953 @Override hide(long startTime, long fadeoutDuration)954 public void hide(long startTime, long fadeoutDuration) { 955 Trace.beginSection("StatusBarKeyguardViewManager#hide"); 956 mKeyguardStateController.notifyKeyguardState(false, 957 mKeyguardStateController.isOccluded()); 958 launchPendingWakeupAction(); 959 960 if (mKeyguardUpdateManager.needsSlowUnlockTransition()) { 961 fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED; 962 } 963 long uptimeMillis = SystemClock.uptimeMillis(); 964 long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis); 965 966 if (mKeyguardStateController.isFlingingToDismissKeyguard()) { 967 final boolean wasFlingingToDismissKeyguard = 968 mKeyguardStateController.isFlingingToDismissKeyguard(); 969 mCentralSurfaces.fadeKeyguardAfterLaunchTransition(new Runnable() { 970 @Override 971 public void run() { 972 mNotificationShadeWindowController.setKeyguardShowing(false); 973 mNotificationShadeWindowController.setKeyguardFadingAway(true); 974 hideBouncer(true /* destroyView */); 975 updateStates(); 976 } 977 }, /* endRunnable */ new Runnable() { 978 @Override 979 public void run() { 980 mCentralSurfaces.hideKeyguard(); 981 mNotificationShadeWindowController.setKeyguardFadingAway(false); 982 983 if (wasFlingingToDismissKeyguard) { 984 mCentralSurfaces.finishKeyguardFadingAway(); 985 } 986 987 mViewMediatorCallback.keyguardGone(); 988 executeAfterKeyguardGoneAction(); 989 } 990 }, /* cancelRunnable */ new Runnable() { 991 @Override 992 public void run() { 993 mNotificationShadeWindowController.setKeyguardFadingAway(false); 994 if (wasFlingingToDismissKeyguard) { 995 mCentralSurfaces.finishKeyguardFadingAway(); 996 } 997 cancelPostAuthActions(); 998 } 999 }); 1000 } else { 1001 executeAfterKeyguardGoneAction(); 1002 mCentralSurfaces.setKeyguardFadingAway(startTime, delay, fadeoutDuration); 1003 mBiometricUnlockController.startKeyguardFadingAway(); 1004 hideBouncer(true /* destroyView */); 1005 1006 boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide(); 1007 if (!staying) { 1008 mNotificationShadeWindowController.setKeyguardFadingAway(true); 1009 wakeAndUnlockDejank(); 1010 mCentralSurfaces.hideKeyguard(); 1011 // hide() will happen asynchronously and might arrive after the scrims 1012 // were already hidden, this means that the transition callback won't 1013 // be triggered anymore and StatusBarWindowController will be forever in 1014 // the fadingAway state. 1015 mCentralSurfaces.updateScrimController(); 1016 } else { 1017 mCentralSurfaces.hideKeyguard(); 1018 mCentralSurfaces.finishKeyguardFadingAway(); 1019 mBiometricUnlockController.finishKeyguardFadingAway(); 1020 } 1021 1022 updateStates(); 1023 mNotificationShadeWindowController.setKeyguardShowing(false); 1024 mViewMediatorCallback.keyguardGone(); 1025 } 1026 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 1027 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN); 1028 Trace.endSection(); 1029 } 1030 1031 @Override onNavigationModeChanged(int mode)1032 public void onNavigationModeChanged(int mode) { 1033 boolean gesturalNav = QuickStepContract.isGesturalMode(mode); 1034 if (gesturalNav != mGesturalNav) { 1035 mGesturalNav = gesturalNav; 1036 updateStates(); 1037 } 1038 } 1039 onThemeChanged()1040 public void onThemeChanged() { 1041 updateResources(); 1042 } 1043 onKeyguardFadedAway()1044 public void onKeyguardFadedAway() { 1045 mNotificationContainer.postDelayed(() -> mNotificationShadeWindowController 1046 .setKeyguardFadingAway(false), 100); 1047 mShadeViewController.resetViewGroupFade(); 1048 mCentralSurfaces.finishKeyguardFadingAway(); 1049 mBiometricUnlockController.finishKeyguardFadingAway(); 1050 } 1051 wakeAndUnlockDejank()1052 private void wakeAndUnlockDejank() { 1053 if (mBiometricUnlockController.isWakeAndUnlock() && mLatencyTracker.isEnabled()) { 1054 BiometricSourceType type = mBiometricUnlockController.getBiometricType(); 1055 mLatencyTracker.onActionEnd(type == BiometricSourceType.FACE 1056 ? LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK 1057 : LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK); 1058 } 1059 } 1060 executeAfterKeyguardGoneAction()1061 private void executeAfterKeyguardGoneAction() { 1062 if (mAfterKeyguardGoneAction != null) { 1063 mAfterKeyguardGoneAction.onDismiss(); 1064 mAfterKeyguardGoneAction = null; 1065 } 1066 mKeyguardGoneCancelAction = null; 1067 mDismissActionWillAnimateOnKeyguard = false; 1068 for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) { 1069 mAfterKeyguardGoneRunnables.get(i).run(); 1070 } 1071 mAfterKeyguardGoneRunnables.clear(); 1072 } 1073 1074 @Override dismissAndCollapse()1075 public void dismissAndCollapse() { 1076 mActivityStarter.executeRunnableDismissingKeyguard( 1077 /* runnable= */ null, 1078 /* cancelAction= */ null, 1079 /* dismissShade= */ true, 1080 /* afterKeyguardGone= */ false, 1081 /* deferred= */ true 1082 ); 1083 } 1084 1085 /** 1086 * WARNING: This method might cause Binder calls. 1087 */ isSecure()1088 public boolean isSecure() { 1089 return mKeyguardSecurityModel.getSecurityMode( 1090 KeyguardUpdateMonitor.getCurrentUser()) != KeyguardSecurityModel.SecurityMode.None; 1091 } 1092 1093 /** 1094 * Returns whether a back invocation can be handled, which depends on whether the keyguard 1095 * is currently showing (which itself is derived from multiple states). 1096 * 1097 * @return whether a back press can be handled right now. 1098 */ canHandleBackPressed()1099 public boolean canHandleBackPressed() { 1100 return primaryBouncerIsShowing(); 1101 } 1102 1103 /** 1104 * Notifies this manager that the back button has been pressed. 1105 */ onBackPressed()1106 public void onBackPressed() { 1107 if (!canHandleBackPressed()) { 1108 return; 1109 } 1110 1111 mCentralSurfaces.endAffordanceLaunch(); 1112 // The second condition is for SIM card locked bouncer 1113 if (primaryBouncerIsScrimmed() && !needsFullscreenBouncer()) { 1114 hideBouncer(false); 1115 updateStates(); 1116 } else { 1117 /* Non-scrimmed bouncers have a special animation tied to the expansion 1118 * of the notification panel. We decide whether to kick this animation off 1119 * by computing the hideImmediately boolean. 1120 */ 1121 boolean hideImmediately = mCentralSurfaces.shouldKeyguardHideImmediately(); 1122 reset(hideImmediately); 1123 if (hideImmediately) { 1124 mStatusBarStateController.setLeaveOpenOnKeyguardHide(false); 1125 } else { 1126 mShadeViewController.expandToNotifications(); 1127 } 1128 } 1129 return; 1130 } 1131 1132 @Override isBouncerShowing()1133 public boolean isBouncerShowing() { 1134 return primaryBouncerIsShowing() || mAlternateBouncerInteractor.isVisibleState(); 1135 } 1136 1137 @Override primaryBouncerIsOrWillBeShowing()1138 public boolean primaryBouncerIsOrWillBeShowing() { 1139 return isBouncerShowing() || isPrimaryBouncerInTransit(); 1140 } 1141 isFullscreenBouncer()1142 public boolean isFullscreenBouncer() { 1143 return mPrimaryBouncerView.getDelegate() != null 1144 && mPrimaryBouncerView.getDelegate().isFullScreenBouncer(); 1145 } 1146 1147 /** 1148 * Clear out any potential actions that were saved to run when the device is unlocked 1149 */ cancelPostAuthActions()1150 public void cancelPostAuthActions() { 1151 if (primaryBouncerIsOrWillBeShowing()) { 1152 return; // allow the primary bouncer to trigger saved actions 1153 } 1154 mAfterKeyguardGoneAction = null; 1155 mDismissActionWillAnimateOnKeyguard = false; 1156 if (mKeyguardGoneCancelAction != null) { 1157 mKeyguardGoneCancelAction.run(); 1158 mKeyguardGoneCancelAction = null; 1159 } 1160 } 1161 getNavBarShowDelay()1162 private long getNavBarShowDelay() { 1163 if (mKeyguardStateController.isKeyguardFadingAway()) { 1164 return mKeyguardStateController.getKeyguardFadingAwayDelay(); 1165 } else if (isBouncerShowing()) { 1166 return NAV_BAR_SHOW_DELAY_BOUNCER; 1167 } else { 1168 // No longer dozing, or remote input is active. No delay. 1169 return 0; 1170 } 1171 } 1172 1173 private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() { 1174 @Override 1175 public void run() { 1176 NavigationBarView view = mCentralSurfaces.getNavigationBarView(); 1177 if (view != null) { 1178 view.setVisibility(View.VISIBLE); 1179 } 1180 mNotificationShadeWindowController.getWindowRootView().getWindowInsetsController() 1181 .show(navigationBars()); 1182 } 1183 }; 1184 updateStates()1185 protected void updateStates() { 1186 if (!mCentralSurfacesRegistered) { 1187 return; 1188 } 1189 boolean showing = mKeyguardStateController.isShowing(); 1190 boolean occluded = mKeyguardStateController.isOccluded(); 1191 boolean primaryBouncerShowing = primaryBouncerIsShowing(); 1192 boolean primaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing(); 1193 boolean primaryBouncerDismissible = !isFullscreenBouncer(); 1194 boolean remoteInputActive = mRemoteInputActive; 1195 1196 if ((primaryBouncerDismissible || !showing || remoteInputActive) 1197 != (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive) 1198 || mFirstUpdate) { 1199 if (primaryBouncerDismissible || !showing || remoteInputActive) { 1200 mPrimaryBouncerInteractor.setBackButtonEnabled(true); 1201 } else { 1202 mPrimaryBouncerInteractor.setBackButtonEnabled(false); 1203 } 1204 } 1205 1206 boolean navBarVisible = isNavBarVisible(); 1207 boolean lastNavBarVisible = getLastNavBarVisible(); 1208 if (navBarVisible != lastNavBarVisible || mFirstUpdate) { 1209 updateNavigationBarVisibility(navBarVisible); 1210 } 1211 1212 boolean isPrimaryBouncerShowingChanged = 1213 primaryBouncerShowing != mLastPrimaryBouncerShowing; 1214 mLastPrimaryBouncerShowing = primaryBouncerShowing; 1215 1216 if (isPrimaryBouncerShowingChanged || mFirstUpdate) { 1217 mNotificationShadeWindowController.setBouncerShowing(primaryBouncerShowing); 1218 mCentralSurfaces.setBouncerShowing(primaryBouncerShowing); 1219 } 1220 if (primaryBouncerIsOrWillBeShowing != mLastPrimaryBouncerIsOrWillBeShowing || mFirstUpdate 1221 || isPrimaryBouncerShowingChanged) { 1222 mKeyguardUpdateManager.sendPrimaryBouncerChanged(primaryBouncerIsOrWillBeShowing, 1223 primaryBouncerShowing); 1224 } 1225 1226 mFirstUpdate = false; 1227 mLastShowing = showing; 1228 mLastGlobalActionsVisible = mGlobalActionsVisible; 1229 mLastOccluded = occluded; 1230 mLastPrimaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing; 1231 mLastBouncerDismissible = primaryBouncerDismissible; 1232 mLastRemoteInputActive = remoteInputActive; 1233 mLastDozing = mDozing; 1234 mLastPulsing = mPulsing; 1235 mLastScreenOffAnimationPlaying = mScreenOffAnimationPlaying; 1236 mLastBiometricMode = mBiometricUnlockController.getMode(); 1237 mLastGesturalNav = mGesturalNav; 1238 mLastIsDocked = mIsDocked; 1239 mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); 1240 } 1241 1242 /** 1243 * Updates the visibility of the nav bar window (which will cause insets changes). 1244 */ updateNavigationBarVisibility(boolean navBarVisible)1245 protected void updateNavigationBarVisibility(boolean navBarVisible) { 1246 if (mCentralSurfaces.getNavigationBarView() != null 1247 || (mTaskbarDelegate != null && mTaskbarDelegate.isInitialized())) { 1248 if (navBarVisible) { 1249 long delay = getNavBarShowDelay(); 1250 if (delay == 0) { 1251 mMakeNavigationBarVisibleRunnable.run(); 1252 } else { 1253 mNotificationContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable, 1254 delay); 1255 } 1256 } else { 1257 mNotificationContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable); 1258 mNotificationShadeWindowController.getWindowRootView().getWindowInsetsController() 1259 .hide(navigationBars()); 1260 } 1261 } 1262 } 1263 1264 /** 1265 * @return Whether the navigation bar should be made visible based on the current state. 1266 */ isNavBarVisible()1267 public boolean isNavBarVisible() { 1268 boolean isWakeAndUnlockPulsing = mBiometricUnlockController != null 1269 && mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING; 1270 boolean keyguardVisible = mKeyguardStateController.isVisible(); 1271 boolean hideWhileDozing = mDozing && !isWakeAndUnlockPulsing; 1272 boolean keyguardWithGestureNav = (keyguardVisible && !mDozing && !mScreenOffAnimationPlaying 1273 || mPulsing && !mIsDocked) 1274 && mGesturalNav; 1275 return (!keyguardVisible && !hideWhileDozing && !mScreenOffAnimationPlaying 1276 || primaryBouncerIsShowing() 1277 || mRemoteInputActive 1278 || keyguardWithGestureNav 1279 || mGlobalActionsVisible); 1280 } 1281 1282 /** 1283 * @return Whether the navigation bar was made visible based on the last known state. 1284 */ getLastNavBarVisible()1285 protected boolean getLastNavBarVisible() { 1286 boolean keyguardShowing = mLastShowing && !mLastOccluded; 1287 boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING; 1288 boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing 1289 && !mLastScreenOffAnimationPlaying || mLastPulsing && !mLastIsDocked) 1290 && mLastGesturalNav; 1291 return (!keyguardShowing && !hideWhileDozing && !mLastScreenOffAnimationPlaying 1292 || mLastPrimaryBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav 1293 || mLastGlobalActionsVisible); 1294 } 1295 shouldDismissOnMenuPressed()1296 public boolean shouldDismissOnMenuPressed() { 1297 return mPrimaryBouncerView.getDelegate() != null 1298 && mPrimaryBouncerView.getDelegate().shouldDismissOnMenuPressed(); 1299 } 1300 interceptMediaKey(KeyEvent event)1301 public boolean interceptMediaKey(KeyEvent event) { 1302 return mPrimaryBouncerView.getDelegate() != null 1303 && mPrimaryBouncerView.getDelegate().interceptMediaKey(event); 1304 } 1305 1306 /** 1307 * @return true if the pre IME back event should be handled 1308 */ dispatchBackKeyEventPreIme()1309 public boolean dispatchBackKeyEventPreIme() { 1310 return mPrimaryBouncerView.getDelegate() != null 1311 && mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme(); 1312 } 1313 readyForKeyguardDone()1314 public void readyForKeyguardDone() { 1315 mViewMediatorCallback.readyForKeyguardDone(); 1316 } 1317 1318 @Override shouldDisableWindowAnimationsForUnlock()1319 public boolean shouldDisableWindowAnimationsForUnlock() { 1320 return false; 1321 } 1322 1323 @Override shouldSubtleWindowAnimationsForUnlock()1324 public boolean shouldSubtleWindowAnimationsForUnlock() { 1325 return false; 1326 } 1327 1328 @Override isGoingToNotificationShade()1329 public boolean isGoingToNotificationShade() { 1330 return mStatusBarStateController.leaveOpenOnKeyguardHide(); 1331 } 1332 isSecure(int userId)1333 public boolean isSecure(int userId) { 1334 return isSecure() || mLockPatternUtils.isSecure(userId); 1335 } 1336 1337 @Override keyguardGoingAway()1338 public void keyguardGoingAway() { 1339 mCentralSurfaces.keyguardGoingAway(); 1340 } 1341 1342 @Override setKeyguardGoingAwayState(boolean isKeyguardGoingAway)1343 public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) { 1344 mNotificationShadeWindowController.setKeyguardGoingAway(isKeyguardGoingAway); 1345 } 1346 1347 @Override onCancelClicked()1348 public void onCancelClicked() { 1349 // No-op 1350 } 1351 1352 /** 1353 * Notifies that the user has authenticated by other means than using the bouncer, for example, 1354 * fingerprint. 1355 */ notifyKeyguardAuthenticated(boolean strongAuth)1356 public void notifyKeyguardAuthenticated(boolean strongAuth) { 1357 mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth); 1358 1359 if (mAlternateBouncerInteractor.isVisibleState()) { 1360 hideAlternateBouncer(false); 1361 executeAfterKeyguardGoneAction(); 1362 } 1363 1364 if (mFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) { 1365 mKeyguardTransitionInteractor.startDismissKeyguardTransition(); 1366 } 1367 } 1368 1369 /** Display security message to relevant KeyguardMessageArea. */ setKeyguardMessage(String message, ColorStateList colorState)1370 public void setKeyguardMessage(String message, ColorStateList colorState) { 1371 if (mAlternateBouncerInteractor.isVisibleState()) { 1372 if (mKeyguardMessageAreaController != null) { 1373 mKeyguardMessageAreaController.setMessage(message); 1374 } 1375 } else { 1376 mPrimaryBouncerInteractor.showMessage(message, colorState); 1377 } 1378 } 1379 1380 @Override getViewRootImpl()1381 public ViewRootImpl getViewRootImpl() { 1382 ViewGroup viewGroup = mNotificationShadeWindowController.getWindowRootView(); 1383 if (viewGroup != null) { 1384 return viewGroup.getViewRootImpl(); 1385 } else { 1386 if (DEBUG) { 1387 Log.d(TAG, "ViewGroup was null, cannot get ViewRootImpl"); 1388 } 1389 return null; 1390 } 1391 } 1392 launchPendingWakeupAction()1393 public void launchPendingWakeupAction() { 1394 DismissWithActionRequest request = mPendingWakeupAction; 1395 mPendingWakeupAction = null; 1396 if (request != null) { 1397 if (mKeyguardStateController.isShowing()) { 1398 dismissWithAction(request.dismissAction, request.cancelAction, 1399 request.afterKeyguardGone, request.message); 1400 } else if (request.dismissAction != null) { 1401 request.dismissAction.onDismiss(); 1402 } 1403 } 1404 } 1405 cancelPendingWakeupAction()1406 public void cancelPendingWakeupAction() { 1407 DismissWithActionRequest request = mPendingWakeupAction; 1408 mPendingWakeupAction = null; 1409 if (request != null && request.cancelAction != null) { 1410 request.cancelAction.run(); 1411 } 1412 } 1413 1414 /** 1415 * Whether the primary bouncer requires scrimming. 1416 */ primaryBouncerNeedsScrimming()1417 public boolean primaryBouncerNeedsScrimming() { 1418 // When a dream overlay is active, scrimming will cause any expansion to immediately expand. 1419 return (mKeyguardStateController.isOccluded() 1420 && !mDreamOverlayStateController.isOverlayActive()) 1421 || primaryBouncerWillDismissWithAction() 1422 || (primaryBouncerIsShowing() && primaryBouncerIsScrimmed()) 1423 || isFullscreenBouncer(); 1424 } 1425 1426 /** 1427 * Apply keyguard configuration from the currently active resources. This can be called when the 1428 * device configuration changes, to re-apply some resources that are qualified on the device 1429 * configuration. 1430 */ updateResources()1431 public void updateResources() { 1432 mPrimaryBouncerInteractor.updateResources(); 1433 } 1434 dump(PrintWriter pw)1435 public void dump(PrintWriter pw) { 1436 pw.println("StatusBarKeyguardViewManager:"); 1437 pw.println(" mRemoteInputActive: " + mRemoteInputActive); 1438 pw.println(" mDozing: " + mDozing); 1439 pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction); 1440 pw.println(" mAfterKeyguardGoneRunnables: " + mAfterKeyguardGoneRunnables); 1441 pw.println(" mPendingWakeupAction: " + mPendingWakeupAction); 1442 pw.println(" isBouncerShowing(): " + isBouncerShowing()); 1443 pw.println(" bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing()); 1444 pw.println(" Registered KeyguardViewManagerCallbacks:"); 1445 for (KeyguardViewManagerCallback callback : mCallbacks) { 1446 pw.println(" " + callback); 1447 } 1448 1449 if (mOccludingAppBiometricUI != null) { 1450 pw.println("mOccludingAppBiometricUI:"); 1451 mOccludingAppBiometricUI.dump(pw); 1452 } 1453 } 1454 1455 @Override onDozingChanged(boolean isDozing)1456 public void onDozingChanged(boolean isDozing) { 1457 setDozing(isDozing); 1458 } 1459 1460 @Override onFoldToAodAnimationChanged()1461 public void onFoldToAodAnimationChanged() { 1462 if (mFoldAodAnimationController != null) { 1463 mScreenOffAnimationPlaying = mFoldAodAnimationController.shouldPlayAnimation(); 1464 } 1465 } 1466 1467 /** 1468 * Add a callback to listen for changes 1469 */ addCallback(KeyguardViewManagerCallback callback)1470 public void addCallback(KeyguardViewManagerCallback callback) { 1471 mCallbacks.add(callback); 1472 } 1473 1474 /** 1475 * Removes callback to stop receiving updates 1476 */ removeCallback(KeyguardViewManagerCallback callback)1477 public void removeCallback(KeyguardViewManagerCallback callback) { 1478 mCallbacks.remove(callback); 1479 } 1480 1481 /** 1482 * Whether qs is currently expanded. 1483 */ getQsExpansion()1484 public float getQsExpansion() { 1485 return mQsExpansion; 1486 } 1487 1488 /** 1489 * Update qs expansion. 1490 */ setQsExpansion(float qsExpansion)1491 public void setQsExpansion(float qsExpansion) { 1492 mQsExpansion = qsExpansion; 1493 for (KeyguardViewManagerCallback callback : mCallbacks) { 1494 callback.onQSExpansionChanged(mQsExpansion); 1495 } 1496 } 1497 1498 /** 1499 * An opportunity for the AlternateBouncer to handle the touch instead of sending 1500 * the touch to NPVC child views. 1501 * @return true if the alternate bouncer should consime the touch and prevent it from 1502 * going to its child views 1503 */ dispatchTouchEvent(MotionEvent event)1504 public boolean dispatchTouchEvent(MotionEvent event) { 1505 if (shouldInterceptTouchEvent(event) 1506 && !mUdfpsOverlayInteractor.isTouchWithinUdfpsArea(event)) { 1507 onTouch(event); 1508 } 1509 return shouldInterceptTouchEvent(event); 1510 } 1511 1512 /** 1513 * Whether the touch should be intercepted by the AlternateBouncer before going to the 1514 * notification shade's child views. 1515 */ shouldInterceptTouchEvent(MotionEvent event)1516 public boolean shouldInterceptTouchEvent(MotionEvent event) { 1517 return mAlternateBouncerInteractor.isVisibleState(); 1518 } 1519 1520 /** 1521 * For any touches on the NPVC, show the primary bouncer if the alternate bouncer is currently 1522 * showing. 1523 */ onTouch(MotionEvent event)1524 public boolean onTouch(MotionEvent event) { 1525 boolean handleTouch = shouldInterceptTouchEvent(event); 1526 if (handleTouch) { 1527 final boolean actionDown = event.getActionMasked() == MotionEvent.ACTION_DOWN; 1528 final boolean actionDownThenUp = mAlternateBouncerInteractor.getReceivedDownTouch() 1529 && event.getActionMasked() == MotionEvent.ACTION_UP; 1530 final boolean udfpsOverlayWillForwardEventsOutsideNotificationShade = 1531 mUdfpsNewTouchDetectionEnabled && mKeyguardUpdateManager.isUdfpsEnrolled(); 1532 final boolean actionOutsideShouldDismissAlternateBouncer = 1533 event.getActionMasked() == MotionEvent.ACTION_OUTSIDE 1534 && !udfpsOverlayWillForwardEventsOutsideNotificationShade; 1535 if (actionDown) { 1536 mAlternateBouncerInteractor.setReceivedDownTouch(true); 1537 } else if ((actionDownThenUp || actionOutsideShouldDismissAlternateBouncer) 1538 && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) { 1539 showPrimaryBouncer(true); 1540 } 1541 } 1542 1543 // Forward NPVC touches to callbacks in case they want to respond to touches 1544 for (KeyguardViewManagerCallback callback: mCallbacks) { 1545 callback.onTouch(event); 1546 } 1547 1548 return handleTouch; 1549 } 1550 1551 /** Update keyguard position based on a tapped X coordinate. */ updateKeyguardPosition(float x)1552 public void updateKeyguardPosition(float x) { 1553 mPrimaryBouncerInteractor.setKeyguardPosition(x); 1554 } 1555 1556 private static class DismissWithActionRequest { 1557 final OnDismissAction dismissAction; 1558 final Runnable cancelAction; 1559 final boolean afterKeyguardGone; 1560 final String message; 1561 DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction, boolean afterKeyguardGone, String message)1562 DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction, 1563 boolean afterKeyguardGone, String message) { 1564 this.dismissAction = dismissAction; 1565 this.cancelAction = cancelAction; 1566 this.afterKeyguardGone = afterKeyguardGone; 1567 this.message = message; 1568 } 1569 } 1570 1571 /** 1572 * Request to authenticate using face. 1573 */ requestFace(boolean request)1574 public void requestFace(boolean request) { 1575 mKeyguardUpdateManager.requestFaceAuthOnOccludingApp(request); 1576 } 1577 1578 /** 1579 * Request to authenticate using the fingerprint sensor. If the fingerprint sensor is udfps, 1580 * uses the color provided by udfpsColor for the fingerprint icon. 1581 */ requestFp(boolean request, int udfpsColor)1582 public void requestFp(boolean request, int udfpsColor) { 1583 mKeyguardUpdateManager.requestFingerprintAuthOnOccludingApp(request); 1584 if (mOccludingAppBiometricUI != null) { 1585 mOccludingAppBiometricUI.requestUdfps(request, udfpsColor); 1586 } 1587 } 1588 1589 /** 1590 * Returns if bouncer expansion is between 0 and 1 non-inclusive. 1591 */ isPrimaryBouncerInTransit()1592 public boolean isPrimaryBouncerInTransit() { 1593 return mPrimaryBouncerInteractor.isInTransit(); 1594 } 1595 1596 /** 1597 * Returns if bouncer is showing 1598 */ primaryBouncerIsShowing()1599 public boolean primaryBouncerIsShowing() { 1600 return mPrimaryBouncerInteractor.isFullyShowing(); 1601 } 1602 1603 /** 1604 * Returns if bouncer is scrimmed 1605 */ primaryBouncerIsScrimmed()1606 public boolean primaryBouncerIsScrimmed() { 1607 return mPrimaryBouncerInteractor.isScrimmed(); 1608 } 1609 1610 /** 1611 * Returns if bouncer is animating away 1612 */ bouncerIsAnimatingAway()1613 public boolean bouncerIsAnimatingAway() { 1614 return mPrimaryBouncerInteractor.isAnimatingAway(); 1615 } 1616 1617 /** 1618 * Returns if bouncer will dismiss with action 1619 */ primaryBouncerWillDismissWithAction()1620 public boolean primaryBouncerWillDismissWithAction() { 1621 return mPrimaryBouncerInteractor.willDismissWithAction(); 1622 } 1623 1624 /** 1625 * Returns if bouncer needs fullscreen bouncer. i.e. sim pin security method 1626 */ needsFullscreenBouncer()1627 public boolean needsFullscreenBouncer() { 1628 KeyguardSecurityModel.SecurityMode mode = mKeyguardSecurityModel.getSecurityMode( 1629 KeyguardUpdateMonitor.getCurrentUser()); 1630 return mode == KeyguardSecurityModel.SecurityMode.SimPin 1631 || mode == KeyguardSecurityModel.SecurityMode.SimPuk; 1632 } 1633 1634 /** 1635 * Delegate used to send show and hide events to an alternate authentication method instead of 1636 * the regular pin/pattern/password bouncer. 1637 */ 1638 public interface OccludingAppBiometricUI { 1639 /** 1640 * Use when an app occluding the keyguard would like to give the user ability to 1641 * unlock the device using udfps. 1642 * 1643 * @param color of the udfps icon. should have proper contrast with its background. only 1644 * used if requestUdfps = true 1645 */ requestUdfps(boolean requestUdfps, int color)1646 void requestUdfps(boolean requestUdfps, int color); 1647 1648 /** 1649 * print information for the alternate bouncer registered 1650 */ dump(PrintWriter pw)1651 void dump(PrintWriter pw); 1652 } 1653 1654 /** 1655 * Callback for KeyguardViewManager state changes. 1656 */ 1657 public interface KeyguardViewManagerCallback { 1658 /** 1659 * Set the amount qs is expanded. For example, swipe down from the top of the 1660 * lock screen to start the full QS expansion. 1661 */ onQSExpansionChanged(float qsExpansion)1662 default void onQSExpansionChanged(float qsExpansion) { } 1663 1664 /** 1665 * Forward touch events to callbacks 1666 */ onTouch(MotionEvent event)1667 default void onTouch(MotionEvent event) { } 1668 } 1669 } 1670