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