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