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