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