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