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