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 
StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils)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 
registerStatusBar(StatusBar statusBar, ViewGroup container, NotificationPanelView notificationPanelView, FingerprintUnlockController fingerprintUnlockController, DismissCallbackRegistry dismissCallbackRegistry)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 
onContainerLayout(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)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
onPanelExpansionChanged(float expansion, boolean tracking)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      */
show(Bundle options)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      */
showBouncerOrKeyguard(boolean hideBouncerWhenShowing)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 
shouldDestroyViewOnReset()218     protected boolean shouldDestroyViewOnReset() {
219         return false;
220     }
221 
hideBouncer(boolean destroyView)222     private void hideBouncer(boolean destroyView) {
223         mBouncer.hide(destroyView);
224         cancelPendingWakeupAction();
225     }
226 
showBouncer(boolean scrimmed)227     public void showBouncer(boolean scrimmed) {
228         if (mShowing && !mBouncer.isShowing()) {
229             mBouncer.show(false /* resetSecuritySelection */, scrimmed);
230         }
231         updateStates();
232     }
233 
dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone)234     public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
235             boolean afterKeyguardGone) {
236         dismissWithAction(r, cancelAction, afterKeyguardGone, null /* message */);
237     }
238 
dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone, String message)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 
isWakeAndUnlocking()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      */
addAfterKeyguardGoneRunnable(Runnable runnable)269     public void addAfterKeyguardGoneRunnable(Runnable runnable) {
270         mAfterKeyguardGoneRunnables.add(runnable);
271     }
272 
273     /**
274      * Reset the state of the view.
275      */
reset(boolean hideBouncerWhenShowing)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 
isGoingToSleepVisibleNotOccluded()291     public boolean isGoingToSleepVisibleNotOccluded() {
292         return mGoingToSleepVisibleNotOccluded;
293     }
294 
onStartedGoingToSleep()295     public void onStartedGoingToSleep() {
296         mGoingToSleepVisibleNotOccluded = isShowing() && !isOccluded();
297     }
298 
onFinishedGoingToSleep()299     public void onFinishedGoingToSleep() {
300         mGoingToSleepVisibleNotOccluded = false;
301         mBouncer.onScreenTurnedOff();
302     }
303 
onStartedWakingUp()304     public void onStartedWakingUp() {
305         // TODO: remove
306     }
307 
onScreenTurningOn()308     public void onScreenTurningOn() {
309         // TODO: remove
310     }
311 
onScreenTurnedOn()312     public void onScreenTurnedOn() {
313         // TODO: remove
314     }
315 
316     @Override
onRemoteInputActive(boolean active)317     public void onRemoteInputActive(boolean active) {
318         mRemoteInputActive = active;
319         updateStates();
320     }
321 
setDozing(boolean dozing)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 
onScreenTurnedOff()336     public void onScreenTurnedOff() {
337         // TODO: remove
338     }
339 
notifyDeviceWakeUpRequested()340     public void notifyDeviceWakeUpRequested() {
341         // TODO: remove
342     }
343 
setNeedsInput(boolean needsInput)344     public void setNeedsInput(boolean needsInput) {
345         mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
346     }
347 
isUnlockWithWallpaper()348     public boolean isUnlockWithWallpaper() {
349         return mStatusBarWindowManager.isShowingWallpaper();
350     }
351 
setOccluded(boolean occluded, boolean animate)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 
isOccluded()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      */
startPreHideAnimation(Runnable finishRunnable)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      */
hide(long startTime, long fadeoutDuration)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 
onDensityOrFontScaleChanged()474     public void onDensityOrFontScaleChanged() {
475         hideBouncer(true /* destroyView */);
476     }
477 
onThemeChanged()478     public void onThemeChanged() {
479         hideBouncer(true /* destroyView */);
480         mBouncer.prepare();
481     }
482 
onKeyguardFadedAway()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 
wakeAndUnlockDejank()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 
executeAfterKeyguardGoneAction()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      */
dismissAndCollapse()516     public void dismissAndCollapse() {
517         mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
518     }
519 
520     /**
521      * WARNING: This method might cause Binder calls.
522      */
isSecure()523     public boolean isSecure() {
524         return mBouncer.isSecure();
525     }
526 
527     /**
528      * @return Whether the keyguard is showing
529      */
isShowing()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      */
onBackPressed(boolean hideImmediately)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 
isBouncerShowing()551     public boolean isBouncerShowing() {
552         return mBouncer.isShowing();
553     }
554 
isFullscreenBouncer()555     public boolean isFullscreenBouncer() {
556         return mBouncer.isFullscreenBouncer();
557     }
558 
getNavBarShowDelay()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 
updateStates()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 
updateNavigationBarVisibility(boolean navBarVisible)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      */
isNavBarVisible()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      */
getLastNavBarVisible()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 
shouldDismissOnMenuPressed()663     public boolean shouldDismissOnMenuPressed() {
664         return mBouncer.shouldDismissOnMenuPressed();
665     }
666 
interceptMediaKey(KeyEvent event)667     public boolean interceptMediaKey(KeyEvent event) {
668         return mBouncer.interceptMediaKey(event);
669     }
670 
readyForKeyguardDone()671     public void readyForKeyguardDone() {
672         mViewMediatorCallback.readyForKeyguardDone();
673     }
674 
shouldDisableWindowAnimationsForUnlock()675     public boolean shouldDisableWindowAnimationsForUnlock() {
676         return mStatusBar.isInLaunchTransition();
677     }
678 
isGoingToNotificationShade()679     public boolean isGoingToNotificationShade() {
680         return mStatusBar.isGoingToNotificationShade();
681     }
682 
isSecure(int userId)683     public boolean isSecure(int userId) {
684         return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId);
685     }
686 
keyguardGoingAway()687     public void keyguardGoingAway() {
688         mStatusBar.keyguardGoingAway();
689     }
690 
animateCollapsePanels(float speedUpFactor)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      */
notifyKeyguardAuthenticated(boolean strongAuth)700     public void notifyKeyguardAuthenticated(boolean strongAuth) {
701         mBouncer.notifyKeyguardAuthenticated(strongAuth);
702     }
703 
showBouncerMessage(String message, int color)704     public void showBouncerMessage(String message, int color) {
705         mBouncer.showMessage(message, color);
706     }
707 
getViewRootImpl()708     public ViewRootImpl getViewRootImpl() {
709         return mStatusBar.getStatusBarView().getViewRootImpl();
710     }
711 
launchPendingWakeupAction()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 
cancelPendingWakeupAction()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 
willDismissWithAction()733     public boolean willDismissWithAction() {
734         return mBouncer.willDismissWithAction();
735     }
736 
bouncerNeedsScrimming()737     public boolean bouncerNeedsScrimming() {
738         return mBouncer.isShowingScrimmed();
739     }
740 
dump(PrintWriter pw)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 
DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction, boolean afterKeyguardGone, String message)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