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