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.ViewRootImpl.NEW_INSETS_MODE_FULL; 20 import static android.view.ViewRootImpl.sNewInsetsMode; 21 import static android.view.WindowInsets.Type.navigationBars; 22 23 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction; 24 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING; 25 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK; 26 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; 27 28 import android.content.ComponentCallbacks2; 29 import android.content.Context; 30 import android.content.res.ColorStateList; 31 import android.os.Bundle; 32 import android.os.SystemClock; 33 import android.view.KeyEvent; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.ViewRootImpl; 37 import android.view.WindowManagerGlobal; 38 39 import androidx.annotation.VisibleForTesting; 40 41 import com.android.internal.util.LatencyTracker; 42 import com.android.internal.widget.LockPatternUtils; 43 import com.android.keyguard.KeyguardUpdateMonitor; 44 import com.android.keyguard.KeyguardUpdateMonitorCallback; 45 import com.android.keyguard.KeyguardViewController; 46 import com.android.keyguard.ViewMediatorCallback; 47 import com.android.settingslib.animation.AppearAnimationUtils; 48 import com.android.systemui.DejankUtils; 49 import com.android.systemui.SystemUIFactory; 50 import com.android.systemui.dock.DockManager; 51 import com.android.systemui.keyguard.DismissCallbackRegistry; 52 import com.android.systemui.plugins.FalsingManager; 53 import com.android.systemui.plugins.statusbar.StatusBarStateController; 54 import com.android.systemui.shared.system.QuickStepContract; 55 import com.android.systemui.shared.system.SysUiStatsLog; 56 import com.android.systemui.statusbar.CrossFadeHelper; 57 import com.android.systemui.statusbar.NotificationMediaManager; 58 import com.android.systemui.statusbar.RemoteInputController; 59 import com.android.systemui.statusbar.StatusBarState; 60 import com.android.systemui.statusbar.SysuiStatusBarStateController; 61 import com.android.systemui.statusbar.notification.ViewGroupFadeHelper; 62 import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback; 63 import com.android.systemui.statusbar.policy.ConfigurationController; 64 import com.android.systemui.statusbar.policy.KeyguardStateController; 65 66 import java.io.PrintWriter; 67 import java.util.ArrayList; 68 69 import javax.inject.Inject; 70 import javax.inject.Singleton; 71 72 /** 73 * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back 74 * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, 75 * which is in turn, reported to this class by the current 76 * {@link com.android.keyguard.KeyguardViewBase}. 77 */ 78 @Singleton 79 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback, 80 StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener, 81 PanelExpansionListener, NavigationModeController.ModeChangedListener, 82 KeyguardViewController { 83 84 // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. 85 private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3; 86 87 // Delay for showing the navigation bar when the bouncer appears. This should be kept in sync 88 // with the appear animations of the PIN/pattern/password views. 89 private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320; 90 91 private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200; 92 93 // Duration of the Keyguard dismissal animation in case the user is currently locked. This is to 94 // make everything a bit slower to bridge a gap until the user is unlocked and home screen has 95 // dranw its first frame. 96 private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000; 97 98 private static String TAG = "StatusBarKeyguardViewManager"; 99 100 protected final Context mContext; 101 private final ConfigurationController mConfigurationController; 102 private final NavigationModeController mNavigationModeController; 103 private final NotificationShadeWindowController mNotificationShadeWindowController; 104 private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() { 105 @Override 106 public void onFullyShown() { 107 updateStates(); 108 mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mContainer, "BOUNCER_VISIBLE"); 109 updateLockIcon(); 110 } 111 112 @Override 113 public void onStartingToHide() { 114 updateStates(); 115 } 116 117 @Override 118 public void onStartingToShow() { 119 updateLockIcon(); 120 } 121 122 @Override 123 public void onFullyHidden() { 124 updateStates(); 125 updateLockIcon(); 126 } 127 }; 128 private final DockManager.DockEventListener mDockEventListener = 129 new DockManager.DockEventListener() { 130 @Override 131 public void onEvent(int event) { 132 boolean isDocked = mDockManager.isDocked(); 133 if (isDocked == mIsDocked) { 134 return; 135 } 136 mIsDocked = isDocked; 137 updateStates(); 138 } 139 }; 140 141 protected LockPatternUtils mLockPatternUtils; 142 protected ViewMediatorCallback mViewMediatorCallback; 143 protected StatusBar mStatusBar; 144 private NotificationPanelViewController mNotificationPanelViewController; 145 private BiometricUnlockController mBiometricUnlockController; 146 147 private ViewGroup mContainer; 148 private ViewGroup mLockIconContainer; 149 private View mNotificationContainer; 150 151 protected KeyguardBouncer mBouncer; 152 protected boolean mShowing; 153 protected boolean mOccluded; 154 protected boolean mRemoteInputActive; 155 private boolean mGlobalActionsVisible = false; 156 private boolean mLastGlobalActionsVisible = false; 157 private boolean mDozing; 158 private boolean mPulsing; 159 private boolean mGesturalNav; 160 private boolean mIsDocked; 161 162 protected boolean mFirstUpdate = true; 163 protected boolean mLastShowing; 164 protected boolean mLastOccluded; 165 private boolean mLastBouncerShowing; 166 private boolean mLastBouncerDismissible; 167 protected boolean mLastRemoteInputActive; 168 private boolean mLastDozing; 169 private boolean mLastGesturalNav; 170 private boolean mLastIsDocked; 171 private boolean mLastPulsing; 172 private int mLastBiometricMode; 173 private boolean mLastLockVisible; 174 175 private OnDismissAction mAfterKeyguardGoneAction; 176 private Runnable mKeyguardGoneCancelAction; 177 private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>(); 178 179 // Dismiss action to be launched when we stop dozing or the keyguard is gone. 180 private DismissWithActionRequest mPendingWakeupAction; 181 private final KeyguardStateController mKeyguardStateController; 182 private final NotificationMediaManager mMediaManager; 183 private final SysuiStatusBarStateController mStatusBarStateController; 184 private final DockManager mDockManager; 185 private final KeyguardUpdateMonitor mKeyguardUpdateManager; 186 private KeyguardBypassController mBypassController; 187 188 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = 189 new KeyguardUpdateMonitorCallback() { 190 @Override 191 public void onEmergencyCallAction() { 192 193 // Since we won't get a setOccluded call we have to reset the view manually such that 194 // the bouncer goes away. 195 if (mOccluded) { 196 reset(true /* hideBouncerWhenShowing */); 197 } 198 } 199 }; 200 201 @Inject StatusBarKeyguardViewManager( Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils, SysuiStatusBarStateController sysuiStatusBarStateController, ConfigurationController configurationController, KeyguardUpdateMonitor keyguardUpdateMonitor, NavigationModeController navigationModeController, DockManager dockManager, NotificationShadeWindowController notificationShadeWindowController, KeyguardStateController keyguardStateController, NotificationMediaManager notificationMediaManager)202 public StatusBarKeyguardViewManager( 203 Context context, 204 ViewMediatorCallback callback, 205 LockPatternUtils lockPatternUtils, 206 SysuiStatusBarStateController sysuiStatusBarStateController, 207 ConfigurationController configurationController, 208 KeyguardUpdateMonitor keyguardUpdateMonitor, 209 NavigationModeController navigationModeController, 210 DockManager dockManager, 211 NotificationShadeWindowController notificationShadeWindowController, 212 KeyguardStateController keyguardStateController, 213 NotificationMediaManager notificationMediaManager) { 214 mContext = context; 215 mViewMediatorCallback = callback; 216 mLockPatternUtils = lockPatternUtils; 217 mConfigurationController = configurationController; 218 mNavigationModeController = navigationModeController; 219 mNotificationShadeWindowController = notificationShadeWindowController; 220 mKeyguardStateController = keyguardStateController; 221 mMediaManager = notificationMediaManager; 222 mKeyguardUpdateManager = keyguardUpdateMonitor; 223 mStatusBarStateController = sysuiStatusBarStateController; 224 mDockManager = dockManager; 225 } 226 227 @Override registerStatusBar(StatusBar statusBar, ViewGroup container, NotificationPanelViewController notificationPanelViewController, BiometricUnlockController biometricUnlockController, DismissCallbackRegistry dismissCallbackRegistry, ViewGroup lockIconContainer, View notificationContainer, KeyguardBypassController bypassController, FalsingManager falsingManager)228 public void registerStatusBar(StatusBar statusBar, 229 ViewGroup container, 230 NotificationPanelViewController notificationPanelViewController, 231 BiometricUnlockController biometricUnlockController, 232 DismissCallbackRegistry dismissCallbackRegistry, 233 ViewGroup lockIconContainer, View notificationContainer, 234 KeyguardBypassController bypassController, FalsingManager falsingManager) { 235 mStatusBar = statusBar; 236 mContainer = container; 237 mLockIconContainer = lockIconContainer; 238 if (mLockIconContainer != null) { 239 mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE; 240 } 241 mBiometricUnlockController = biometricUnlockController; 242 mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, 243 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry, 244 mExpansionCallback, mKeyguardStateController, falsingManager, bypassController); 245 mNotificationPanelViewController = notificationPanelViewController; 246 notificationPanelViewController.addExpansionListener(this); 247 mBypassController = bypassController; 248 mNotificationContainer = notificationContainer; 249 250 registerListeners(); 251 } 252 registerListeners()253 private void registerListeners() { 254 mKeyguardUpdateManager.registerCallback(mUpdateMonitorCallback); 255 mStatusBarStateController.addCallback(this); 256 mConfigurationController.addCallback(this); 257 mGesturalNav = QuickStepContract.isGesturalMode( 258 mNavigationModeController.addListener(this)); 259 if (mDockManager != null) { 260 mDockManager.addListener(mDockEventListener); 261 mIsDocked = mDockManager.isDocked(); 262 } 263 } 264 265 @Override onPanelExpansionChanged(float expansion, boolean tracking)266 public void onPanelExpansionChanged(float expansion, boolean tracking) { 267 // We don't want to translate the bounce when: 268 // • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to 269 // conserve the original animation. 270 // • The user quickly taps on the display and we show "swipe up to unlock." 271 // • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY 272 // • Full-screen user switcher is displayed. 273 if (mNotificationPanelViewController.isUnlockHintRunning()) { 274 mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN); 275 } else if (bouncerNeedsScrimming()) { 276 mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); 277 } else if (mShowing) { 278 if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) { 279 mBouncer.setExpansion(expansion); 280 } 281 if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking 282 && !mKeyguardStateController.canDismissLockScreen() 283 && !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) { 284 mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */); 285 } 286 } else if (mPulsing && expansion == KeyguardBouncer.EXPANSION_VISIBLE) { 287 // Panel expanded while pulsing but didn't translate the bouncer (because we are 288 // unlocked.) Let's simply wake-up to dismiss the lock screen. 289 mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mContainer, "BOUNCER_VISIBLE"); 290 } 291 } 292 293 @Override onQsExpansionChanged(float expansion)294 public void onQsExpansionChanged(float expansion) { 295 updateLockIcon(); 296 } 297 298 /** 299 * Update the global actions visibility state in order to show the navBar when active. 300 */ setGlobalActionsVisible(boolean isVisible)301 public void setGlobalActionsVisible(boolean isVisible) { 302 mGlobalActionsVisible = isVisible; 303 updateStates(); 304 } 305 updateLockIcon()306 private void updateLockIcon() { 307 // Not all form factors have a lock icon 308 if (mLockIconContainer == null) { 309 return; 310 } 311 boolean keyguardWithoutQs = mStatusBarStateController.getState() == StatusBarState.KEYGUARD 312 && !mNotificationPanelViewController.isQsExpanded(); 313 boolean lockVisible = (mBouncer.isShowing() || keyguardWithoutQs) 314 && !mBouncer.isAnimatingAway() && !mKeyguardStateController.isKeyguardFadingAway(); 315 316 if (mLastLockVisible != lockVisible) { 317 mLastLockVisible = lockVisible; 318 if (lockVisible) { 319 CrossFadeHelper.fadeIn(mLockIconContainer, 320 AppearAnimationUtils.DEFAULT_APPEAR_DURATION /* duration */, 321 0 /* delay */); 322 } else { 323 final long duration; 324 final int delay; 325 if (needsBypassFading()) { 326 duration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION; 327 delay = 0; 328 } else { 329 duration = AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2; 330 delay = 120; 331 } 332 CrossFadeHelper.fadeOut(mLockIconContainer, duration, delay, null /* runnable */); 333 } 334 } 335 } 336 337 /** 338 * Show the keyguard. Will handle creating and attaching to the view manager 339 * lazily. 340 */ 341 @Override show(Bundle options)342 public void show(Bundle options) { 343 mShowing = true; 344 mNotificationShadeWindowController.setKeyguardShowing(true); 345 mKeyguardStateController.notifyKeyguardState(mShowing, 346 mKeyguardStateController.isOccluded()); 347 reset(true /* hideBouncerWhenShowing */); 348 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 349 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); 350 } 351 352 /** 353 * Shows the notification keyguard or the bouncer depending on 354 * {@link KeyguardBouncer#needsFullscreenBouncer()}. 355 */ showBouncerOrKeyguard(boolean hideBouncerWhenShowing)356 protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) { 357 if (mBouncer.needsFullscreenBouncer() && !mDozing) { 358 // The keyguard might be showing (already). So we need to hide it. 359 mStatusBar.hideKeyguard(); 360 mBouncer.show(true /* resetSecuritySelection */); 361 } else { 362 mStatusBar.showKeyguard(); 363 if (hideBouncerWhenShowing) { 364 hideBouncer(shouldDestroyViewOnReset() /* destroyView */); 365 mBouncer.prepare(); 366 } 367 } 368 updateStates(); 369 } 370 shouldDestroyViewOnReset()371 protected boolean shouldDestroyViewOnReset() { 372 return false; 373 } 374 375 @VisibleForTesting hideBouncer(boolean destroyView)376 void hideBouncer(boolean destroyView) { 377 if (mBouncer == null) { 378 return; 379 } 380 if (mShowing) { 381 // If we were showing the bouncer and then aborting, we need to also clear out any 382 // potential actions unless we actually unlocked. 383 mAfterKeyguardGoneAction = null; 384 if (mKeyguardGoneCancelAction != null) { 385 mKeyguardGoneCancelAction.run(); 386 mKeyguardGoneCancelAction = null; 387 } 388 } 389 mBouncer.hide(destroyView); 390 cancelPendingWakeupAction(); 391 } 392 393 /** 394 * Shows the keyguard bouncer - the password challenge on the lock screen 395 * 396 * @param scrimmed true when the bouncer should show scrimmed, false when the user will be 397 * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)} 398 */ showBouncer(boolean scrimmed)399 public void showBouncer(boolean scrimmed) { 400 if (mShowing && !mBouncer.isShowing()) { 401 mBouncer.show(false /* resetSecuritySelection */, scrimmed); 402 } 403 updateStates(); 404 } 405 dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone)406 public void dismissWithAction(OnDismissAction r, Runnable cancelAction, 407 boolean afterKeyguardGone) { 408 dismissWithAction(r, cancelAction, afterKeyguardGone, null /* message */); 409 } 410 dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone, String message)411 public void dismissWithAction(OnDismissAction r, Runnable cancelAction, 412 boolean afterKeyguardGone, String message) { 413 if (mShowing) { 414 cancelPendingWakeupAction(); 415 // If we're dozing, this needs to be delayed until after we wake up - unless we're 416 // wake-and-unlocking, because there dozing will last until the end of the transition. 417 if (mDozing && !isWakeAndUnlocking()) { 418 mPendingWakeupAction = new DismissWithActionRequest( 419 r, cancelAction, afterKeyguardGone, message); 420 return; 421 } 422 423 if (!afterKeyguardGone) { 424 mBouncer.showWithDismissAction(r, cancelAction); 425 } else { 426 mAfterKeyguardGoneAction = r; 427 mKeyguardGoneCancelAction = cancelAction; 428 mBouncer.show(false /* resetSecuritySelection */); 429 } 430 } 431 updateStates(); 432 } 433 isWakeAndUnlocking()434 private boolean isWakeAndUnlocking() { 435 int mode = mBiometricUnlockController.getMode(); 436 return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING; 437 } 438 439 /** 440 * Adds a {@param runnable} to be executed after Keyguard is gone. 441 */ addAfterKeyguardGoneRunnable(Runnable runnable)442 public void addAfterKeyguardGoneRunnable(Runnable runnable) { 443 mAfterKeyguardGoneRunnables.add(runnable); 444 } 445 446 @Override reset(boolean hideBouncerWhenShowing)447 public void reset(boolean hideBouncerWhenShowing) { 448 if (mShowing) { 449 if (mOccluded && !mDozing) { 450 mStatusBar.hideKeyguard(); 451 if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) { 452 hideBouncer(false /* destroyView */); 453 } 454 } else { 455 showBouncerOrKeyguard(hideBouncerWhenShowing); 456 } 457 mKeyguardUpdateManager.sendKeyguardReset(); 458 updateStates(); 459 } 460 } 461 462 @Override onStartedWakingUp()463 public void onStartedWakingUp() { 464 mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() 465 .setAnimationsDisabled(false); 466 } 467 468 @Override onStartedGoingToSleep()469 public void onStartedGoingToSleep() { 470 mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() 471 .setAnimationsDisabled(true); 472 } 473 474 @Override onFinishedGoingToSleep()475 public void onFinishedGoingToSleep() { 476 mBouncer.onScreenTurnedOff(); 477 } 478 479 @Override onRemoteInputActive(boolean active)480 public void onRemoteInputActive(boolean active) { 481 mRemoteInputActive = active; 482 updateStates(); 483 } 484 setDozing(boolean dozing)485 private void setDozing(boolean dozing) { 486 if (mDozing != dozing) { 487 mDozing = dozing; 488 if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) { 489 reset(dozing /* hideBouncerWhenShowing */); 490 } 491 updateStates(); 492 493 if (!dozing) { 494 launchPendingWakeupAction(); 495 } 496 } 497 } 498 499 /** 500 * If {@link StatusBar} is pulsing. 501 */ setPulsing(boolean pulsing)502 public void setPulsing(boolean pulsing) { 503 if (mPulsing != pulsing) { 504 mPulsing = pulsing; 505 updateStates(); 506 } 507 } 508 509 @Override setNeedsInput(boolean needsInput)510 public void setNeedsInput(boolean needsInput) { 511 mNotificationShadeWindowController.setKeyguardNeedsInput(needsInput); 512 } 513 514 @Override isUnlockWithWallpaper()515 public boolean isUnlockWithWallpaper() { 516 return mNotificationShadeWindowController.isShowingWallpaper(); 517 } 518 519 @Override setOccluded(boolean occluded, boolean animate)520 public void setOccluded(boolean occluded, boolean animate) { 521 mStatusBar.setOccluded(occluded); 522 if (occluded && !mOccluded && mShowing) { 523 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 524 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); 525 if (mStatusBar.isInLaunchTransition()) { 526 mOccluded = true; 527 mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, 528 new Runnable() { 529 @Override 530 public void run() { 531 mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); 532 reset(true /* hideBouncerWhenShowing */); 533 } 534 }); 535 return; 536 } 537 } else if (!occluded && mOccluded && mShowing) { 538 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 539 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); 540 } 541 boolean isOccluding = !mOccluded && occluded; 542 mOccluded = occluded; 543 if (mShowing) { 544 mMediaManager.updateMediaMetaData(false, animate && !occluded); 545 } 546 mNotificationShadeWindowController.setKeyguardOccluded(occluded); 547 548 // setDozing(false) will call reset once we stop dozing. 549 if (!mDozing) { 550 // If Keyguard is reshown, don't hide the bouncer as it might just have been requested 551 // by a FLAG_DISMISS_KEYGUARD_ACTIVITY. 552 reset(isOccluding /* hideBouncerWhenShowing*/); 553 } 554 if (animate && !occluded && mShowing && !mBouncer.isShowing()) { 555 mStatusBar.animateKeyguardUnoccluding(); 556 } 557 } 558 isOccluded()559 public boolean isOccluded() { 560 return mOccluded; 561 } 562 563 @Override startPreHideAnimation(Runnable finishRunnable)564 public void startPreHideAnimation(Runnable finishRunnable) { 565 if (mBouncer.isShowing()) { 566 mBouncer.startPreHideAnimation(finishRunnable); 567 mStatusBar.onBouncerPreHideAnimation(); 568 } else if (finishRunnable != null) { 569 finishRunnable.run(); 570 } 571 mNotificationPanelViewController.blockExpansionForCurrentTouch(); 572 updateLockIcon(); 573 } 574 575 @Override hide(long startTime, long fadeoutDuration)576 public void hide(long startTime, long fadeoutDuration) { 577 mShowing = false; 578 mKeyguardStateController.notifyKeyguardState(mShowing, 579 mKeyguardStateController.isOccluded()); 580 launchPendingWakeupAction(); 581 582 if (mKeyguardUpdateManager.needsSlowUnlockTransition()) { 583 fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED; 584 } 585 long uptimeMillis = SystemClock.uptimeMillis(); 586 long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis); 587 588 if (mStatusBar.isInLaunchTransition() ) { 589 mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() { 590 @Override 591 public void run() { 592 mNotificationShadeWindowController.setKeyguardShowing(false); 593 mNotificationShadeWindowController.setKeyguardFadingAway(true); 594 hideBouncer(true /* destroyView */); 595 updateStates(); 596 } 597 }, new Runnable() { 598 @Override 599 public void run() { 600 mStatusBar.hideKeyguard(); 601 mNotificationShadeWindowController.setKeyguardFadingAway(false); 602 mViewMediatorCallback.keyguardGone(); 603 executeAfterKeyguardGoneAction(); 604 } 605 }); 606 } else { 607 executeAfterKeyguardGoneAction(); 608 boolean wakeUnlockPulsing = 609 mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING; 610 boolean needsFading = needsBypassFading(); 611 if (needsFading) { 612 delay = 0; 613 fadeoutDuration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION; 614 } else if (wakeUnlockPulsing) { 615 delay = 0; 616 fadeoutDuration = 240; 617 } 618 mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading); 619 mBiometricUnlockController.startKeyguardFadingAway(); 620 hideBouncer(true /* destroyView */); 621 if (wakeUnlockPulsing) { 622 if (needsFading) { 623 ViewGroupFadeHelper.fadeOutAllChildrenExcept( 624 mNotificationPanelViewController.getView(), 625 mNotificationContainer, 626 fadeoutDuration, 627 () -> { 628 mStatusBar.hideKeyguard(); 629 onKeyguardFadedAway(); 630 }); 631 } else { 632 mStatusBar.fadeKeyguardWhilePulsing(); 633 } 634 wakeAndUnlockDejank(); 635 } else { 636 boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide(); 637 if (!staying) { 638 mNotificationShadeWindowController.setKeyguardFadingAway(true); 639 if (needsFading) { 640 ViewGroupFadeHelper.fadeOutAllChildrenExcept( 641 mNotificationPanelViewController.getView(), 642 mNotificationContainer, 643 fadeoutDuration, 644 () -> { 645 mStatusBar.hideKeyguard(); 646 }); 647 } else { 648 mStatusBar.hideKeyguard(); 649 } 650 // hide() will happen asynchronously and might arrive after the scrims 651 // were already hidden, this means that the transition callback won't 652 // be triggered anymore and StatusBarWindowController will be forever in 653 // the fadingAway state. 654 mStatusBar.updateScrimController(); 655 wakeAndUnlockDejank(); 656 } else { 657 mStatusBar.hideKeyguard(); 658 mStatusBar.finishKeyguardFadingAway(); 659 mBiometricUnlockController.finishKeyguardFadingAway(); 660 } 661 } 662 updateLockIcon(); 663 updateStates(); 664 mNotificationShadeWindowController.setKeyguardShowing(false); 665 mViewMediatorCallback.keyguardGone(); 666 } 667 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, 668 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN); 669 } 670 needsBypassFading()671 private boolean needsBypassFading() { 672 return (mBiometricUnlockController.getMode() == MODE_UNLOCK_FADING 673 || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING 674 || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK) 675 && mBypassController.getBypassEnabled(); 676 } 677 678 @Override onDensityOrFontScaleChanged()679 public void onDensityOrFontScaleChanged() { 680 hideBouncer(true /* destroyView */); 681 } 682 683 @Override onNavigationModeChanged(int mode)684 public void onNavigationModeChanged(int mode) { 685 boolean gesturalNav = QuickStepContract.isGesturalMode(mode); 686 if (gesturalNav != mGesturalNav) { 687 mGesturalNav = gesturalNav; 688 updateStates(); 689 } 690 } 691 onThemeChanged()692 public void onThemeChanged() { 693 hideBouncer(true /* destroyView */); 694 mBouncer.prepare(); 695 } 696 onKeyguardFadedAway()697 public void onKeyguardFadedAway() { 698 mContainer.postDelayed(() -> mNotificationShadeWindowController 699 .setKeyguardFadingAway(false), 100); 700 ViewGroupFadeHelper.reset(mNotificationPanelViewController.getView()); 701 mStatusBar.finishKeyguardFadingAway(); 702 mBiometricUnlockController.finishKeyguardFadingAway(); 703 WindowManagerGlobal.getInstance().trimMemory( 704 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); 705 706 } 707 wakeAndUnlockDejank()708 private void wakeAndUnlockDejank() { 709 if (mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK 710 && LatencyTracker.isEnabled(mContext)) { 711 DejankUtils.postAfterTraversal(() -> 712 LatencyTracker.getInstance(mContext).onActionEnd( 713 LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK)); 714 } 715 } 716 executeAfterKeyguardGoneAction()717 private void executeAfterKeyguardGoneAction() { 718 if (mAfterKeyguardGoneAction != null) { 719 mAfterKeyguardGoneAction.onDismiss(); 720 mAfterKeyguardGoneAction = null; 721 } 722 mKeyguardGoneCancelAction = null; 723 for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) { 724 mAfterKeyguardGoneRunnables.get(i).run(); 725 } 726 mAfterKeyguardGoneRunnables.clear(); 727 } 728 729 @Override dismissAndCollapse()730 public void dismissAndCollapse() { 731 mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true); 732 } 733 734 /** 735 * WARNING: This method might cause Binder calls. 736 */ isSecure()737 public boolean isSecure() { 738 return mBouncer.isSecure(); 739 } 740 741 @Override isShowing()742 public boolean isShowing() { 743 return mShowing; 744 } 745 746 /** 747 * Notifies this manager that the back button has been pressed. 748 * 749 * @param hideImmediately Hide bouncer when {@code true}, keep it around otherwise. 750 * Non-scrimmed bouncers have a special animation tied to the expansion 751 * of the notification panel. 752 * @return whether the back press has been handled 753 */ onBackPressed(boolean hideImmediately)754 public boolean onBackPressed(boolean hideImmediately) { 755 if (mBouncer.isShowing()) { 756 mStatusBar.endAffordanceLaunch(); 757 // The second condition is for SIM card locked bouncer 758 if (mBouncer.isScrimmed() && !mBouncer.needsFullscreenBouncer()) { 759 hideBouncer(false); 760 updateStates(); 761 } else { 762 reset(hideImmediately); 763 } 764 return true; 765 } 766 return false; 767 } 768 769 @Override isBouncerShowing()770 public boolean isBouncerShowing() { 771 return mBouncer.isShowing(); 772 } 773 774 @Override bouncerIsOrWillBeShowing()775 public boolean bouncerIsOrWillBeShowing() { 776 return mBouncer.isShowing() || mBouncer.inTransit(); 777 } 778 isFullscreenBouncer()779 public boolean isFullscreenBouncer() { 780 return mBouncer.isFullscreenBouncer(); 781 } 782 getNavBarShowDelay()783 private long getNavBarShowDelay() { 784 if (mKeyguardStateController.isKeyguardFadingAway()) { 785 return mKeyguardStateController.getKeyguardFadingAwayDelay(); 786 } else if (mBouncer.isShowing()) { 787 return NAV_BAR_SHOW_DELAY_BOUNCER; 788 } else { 789 // No longer dozing, or remote input is active. No delay. 790 return 0; 791 } 792 } 793 794 private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() { 795 @Override 796 public void run() { 797 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) { 798 mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() 799 .show(navigationBars()); 800 } else { 801 mStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE); 802 } 803 } 804 }; 805 updateStates()806 protected void updateStates() { 807 int vis = mContainer.getSystemUiVisibility(); 808 boolean showing = mShowing; 809 boolean occluded = mOccluded; 810 boolean bouncerShowing = mBouncer.isShowing(); 811 boolean bouncerDismissible = !mBouncer.isFullscreenBouncer(); 812 boolean remoteInputActive = mRemoteInputActive; 813 814 if ((bouncerDismissible || !showing || remoteInputActive) != 815 (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive) 816 || mFirstUpdate) { 817 if (bouncerDismissible || !showing || remoteInputActive) { 818 mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK); 819 } else { 820 mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK); 821 } 822 } 823 824 boolean navBarVisible = isNavBarVisible(); 825 boolean lastNavBarVisible = getLastNavBarVisible(); 826 if (navBarVisible != lastNavBarVisible || mFirstUpdate) { 827 updateNavigationBarVisibility(navBarVisible); 828 } 829 830 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { 831 mNotificationShadeWindowController.setBouncerShowing(bouncerShowing); 832 mStatusBar.setBouncerShowing(bouncerShowing); 833 updateLockIcon(); 834 } 835 836 if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) { 837 mKeyguardUpdateManager.onKeyguardVisibilityChanged(showing && !occluded); 838 } 839 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { 840 mKeyguardUpdateManager.sendKeyguardBouncerChanged(bouncerShowing); 841 } 842 843 mFirstUpdate = false; 844 mLastShowing = showing; 845 mLastGlobalActionsVisible = mGlobalActionsVisible; 846 mLastOccluded = occluded; 847 mLastBouncerShowing = bouncerShowing; 848 mLastBouncerDismissible = bouncerDismissible; 849 mLastRemoteInputActive = remoteInputActive; 850 mLastDozing = mDozing; 851 mLastPulsing = mPulsing; 852 mLastBiometricMode = mBiometricUnlockController.getMode(); 853 mLastGesturalNav = mGesturalNav; 854 mLastIsDocked = mIsDocked; 855 mStatusBar.onKeyguardViewManagerStatesUpdated(); 856 } 857 updateNavigationBarVisibility(boolean navBarVisible)858 protected void updateNavigationBarVisibility(boolean navBarVisible) { 859 if (mStatusBar.getNavigationBarView() != null) { 860 if (navBarVisible) { 861 long delay = getNavBarShowDelay(); 862 if (delay == 0) { 863 mMakeNavigationBarVisibleRunnable.run(); 864 } else { 865 mContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable, 866 delay); 867 } 868 } else { 869 mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable); 870 if (sNewInsetsMode == NEW_INSETS_MODE_FULL) { 871 mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() 872 .hide(navigationBars()); 873 } else { 874 mStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE); 875 } 876 } 877 } 878 } 879 880 /** 881 * @return Whether the navigation bar should be made visible based on the current state. 882 */ isNavBarVisible()883 protected boolean isNavBarVisible() { 884 int biometricMode = mBiometricUnlockController.getMode(); 885 boolean keyguardShowing = mShowing && !mOccluded; 886 boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING; 887 boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked) 888 && mGesturalNav; 889 return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing() 890 || mRemoteInputActive || keyguardWithGestureNav 891 || mGlobalActionsVisible); 892 } 893 894 /** 895 * @return Whether the navigation bar was made visible based on the last known state. 896 */ getLastNavBarVisible()897 protected boolean getLastNavBarVisible() { 898 boolean keyguardShowing = mLastShowing && !mLastOccluded; 899 boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING; 900 boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing 901 || mLastPulsing && !mLastIsDocked) && mLastGesturalNav; 902 return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing 903 || mLastRemoteInputActive || keyguardWithGestureNav 904 || mLastGlobalActionsVisible); 905 } 906 shouldDismissOnMenuPressed()907 public boolean shouldDismissOnMenuPressed() { 908 return mBouncer.shouldDismissOnMenuPressed(); 909 } 910 interceptMediaKey(KeyEvent event)911 public boolean interceptMediaKey(KeyEvent event) { 912 return mBouncer.interceptMediaKey(event); 913 } 914 readyForKeyguardDone()915 public void readyForKeyguardDone() { 916 mViewMediatorCallback.readyForKeyguardDone(); 917 } 918 919 @Override shouldDisableWindowAnimationsForUnlock()920 public boolean shouldDisableWindowAnimationsForUnlock() { 921 return mStatusBar.isInLaunchTransition(); 922 } 923 924 @Override shouldSubtleWindowAnimationsForUnlock()925 public boolean shouldSubtleWindowAnimationsForUnlock() { 926 return needsBypassFading(); 927 } 928 929 @Override isGoingToNotificationShade()930 public boolean isGoingToNotificationShade() { 931 return mStatusBarStateController.leaveOpenOnKeyguardHide(); 932 } 933 isSecure(int userId)934 public boolean isSecure(int userId) { 935 return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId); 936 } 937 938 @Override keyguardGoingAway()939 public void keyguardGoingAway() { 940 mStatusBar.keyguardGoingAway(); 941 } 942 943 @Override setKeyguardGoingAwayState(boolean isKeyguardGoingAway)944 public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) { 945 mNotificationShadeWindowController.setKeyguardGoingAway(isKeyguardGoingAway); 946 } 947 948 @Override onCancelClicked()949 public void onCancelClicked() { 950 // No-op 951 } 952 953 /** 954 * Notifies that the user has authenticated by other means than using the bouncer, for example, 955 * fingerprint. 956 */ notifyKeyguardAuthenticated(boolean strongAuth)957 public void notifyKeyguardAuthenticated(boolean strongAuth) { 958 mBouncer.notifyKeyguardAuthenticated(strongAuth); 959 } 960 showBouncerMessage(String message, ColorStateList colorState)961 public void showBouncerMessage(String message, ColorStateList colorState) { 962 mBouncer.showMessage(message, colorState); 963 } 964 965 @Override getViewRootImpl()966 public ViewRootImpl getViewRootImpl() { 967 return mStatusBar.getStatusBarView().getViewRootImpl(); 968 } 969 launchPendingWakeupAction()970 public void launchPendingWakeupAction() { 971 DismissWithActionRequest request = mPendingWakeupAction; 972 mPendingWakeupAction = null; 973 if (request != null) { 974 if (mShowing) { 975 dismissWithAction(request.dismissAction, request.cancelAction, 976 request.afterKeyguardGone, request.message); 977 } else if (request.dismissAction != null) { 978 request.dismissAction.onDismiss(); 979 } 980 } 981 } 982 cancelPendingWakeupAction()983 public void cancelPendingWakeupAction() { 984 DismissWithActionRequest request = mPendingWakeupAction; 985 mPendingWakeupAction = null; 986 if (request != null && request.cancelAction != null) { 987 request.cancelAction.run(); 988 } 989 } 990 bouncerNeedsScrimming()991 public boolean bouncerNeedsScrimming() { 992 return mOccluded || mBouncer.willDismissWithAction() 993 || mStatusBar.isFullScreenUserSwitcherState() 994 || (mBouncer.isShowing() && mBouncer.isScrimmed()) 995 || mBouncer.isFullscreenBouncer(); 996 } 997 dump(PrintWriter pw)998 public void dump(PrintWriter pw) { 999 pw.println("StatusBarKeyguardViewManager:"); 1000 pw.println(" mShowing: " + mShowing); 1001 pw.println(" mOccluded: " + mOccluded); 1002 pw.println(" mRemoteInputActive: " + mRemoteInputActive); 1003 pw.println(" mDozing: " + mDozing); 1004 pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction); 1005 pw.println(" mAfterKeyguardGoneRunnables: " + mAfterKeyguardGoneRunnables); 1006 pw.println(" mPendingWakeupAction: " + mPendingWakeupAction); 1007 1008 if (mBouncer != null) { 1009 mBouncer.dump(pw); 1010 } 1011 } 1012 1013 @Override onStateChanged(int newState)1014 public void onStateChanged(int newState) { 1015 updateLockIcon(); 1016 } 1017 1018 @Override onDozingChanged(boolean isDozing)1019 public void onDozingChanged(boolean isDozing) { 1020 setDozing(isDozing); 1021 } 1022 getBouncer()1023 public KeyguardBouncer getBouncer() { 1024 return mBouncer; 1025 } 1026 1027 private static class DismissWithActionRequest { 1028 final OnDismissAction dismissAction; 1029 final Runnable cancelAction; 1030 final boolean afterKeyguardGone; 1031 final String message; 1032 DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction, boolean afterKeyguardGone, String message)1033 DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction, 1034 boolean afterKeyguardGone, String message) { 1035 this.dismissAction = dismissAction; 1036 this.cancelAction = cancelAction; 1037 this.afterKeyguardGone = afterKeyguardGone; 1038 this.message = message; 1039 } 1040 } 1041 } 1042