OSDN Git Service

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