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.util.StatsLog;
     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.annotations.VisibleForTesting;
     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.systemui.DejankUtils;
     41 import com.android.systemui.Dependency;
     42 import com.android.systemui.SystemUIFactory;
     43 import com.android.systemui.keyguard.DismissCallbackRegistry;
     44 import com.android.systemui.statusbar.CommandQueue;
     45 import com.android.systemui.statusbar.RemoteInputController;
     46 import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
     47 
     48 import java.io.PrintWriter;
     49 import 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  */
     57 public 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