• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.systemui.statusbar.phone;
18 
19 import static android.view.WindowInsets.Type.navigationBars;
20 
21 import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
22 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
23 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
24 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
25 
26 import android.content.ComponentCallbacks2;
27 import android.content.Context;
28 import android.content.res.ColorStateList;
29 import android.hardware.biometrics.BiometricSourceType;
30 import android.os.Bundle;
31 import android.os.SystemClock;
32 import android.os.Trace;
33 import android.util.Log;
34 import android.view.KeyEvent;
35 import android.view.MotionEvent;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.view.ViewRootImpl;
39 import android.view.WindowManagerGlobal;
40 import android.window.BackEvent;
41 import android.window.OnBackAnimationCallback;
42 import android.window.OnBackInvokedDispatcher;
43 
44 import androidx.annotation.NonNull;
45 import androidx.annotation.Nullable;
46 import androidx.annotation.VisibleForTesting;
47 
48 import com.android.internal.util.LatencyTracker;
49 import com.android.internal.widget.LockPatternUtils;
50 import com.android.keyguard.AuthKeyguardMessageArea;
51 import com.android.keyguard.KeyguardMessageAreaController;
52 import com.android.keyguard.KeyguardSecurityModel;
53 import com.android.keyguard.KeyguardUpdateMonitor;
54 import com.android.keyguard.KeyguardUpdateMonitorCallback;
55 import com.android.keyguard.KeyguardViewController;
56 import com.android.keyguard.ViewMediatorCallback;
57 import com.android.systemui.dagger.SysUISingleton;
58 import com.android.systemui.dock.DockManager;
59 import com.android.systemui.dreams.DreamOverlayStateController;
60 import com.android.systemui.flags.FeatureFlags;
61 import com.android.systemui.flags.Flags;
62 import com.android.systemui.keyguard.data.BouncerView;
63 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
64 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
65 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
66 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
67 import com.android.systemui.navigationbar.NavigationBarView;
68 import com.android.systemui.navigationbar.NavigationModeController;
69 import com.android.systemui.navigationbar.TaskbarDelegate;
70 import com.android.systemui.plugins.statusbar.StatusBarStateController;
71 import com.android.systemui.shade.NotificationPanelViewController;
72 import com.android.systemui.shade.ShadeController;
73 import com.android.systemui.shade.ShadeExpansionChangeEvent;
74 import com.android.systemui.shade.ShadeExpansionListener;
75 import com.android.systemui.shade.ShadeExpansionStateManager;
76 import com.android.systemui.shared.system.QuickStepContract;
77 import com.android.systemui.shared.system.SysUiStatsLog;
78 import com.android.systemui.statusbar.NotificationMediaManager;
79 import com.android.systemui.statusbar.NotificationShadeWindowController;
80 import com.android.systemui.statusbar.RemoteInputController;
81 import com.android.systemui.statusbar.StatusBarState;
82 import com.android.systemui.statusbar.SysuiStatusBarStateController;
83 import com.android.systemui.statusbar.policy.ConfigurationController;
84 import com.android.systemui.statusbar.policy.KeyguardStateController;
85 import com.android.systemui.unfold.FoldAodAnimationController;
86 import com.android.systemui.unfold.SysUIUnfoldComponent;
87 
88 import java.io.PrintWriter;
89 import java.util.ArrayList;
90 import java.util.HashSet;
91 import java.util.Objects;
92 import java.util.Optional;
93 import java.util.Set;
94 
95 import javax.inject.Inject;
96 
97 import dagger.Lazy;
98 
99 /**
100  * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
101  * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
102  * which is in turn, reported to this class by the current
103  * {@link com.android.keyguard.KeyguardViewController}.
104  */
105 @SysUISingleton
106 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
107         StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
108         ShadeExpansionListener, NavigationModeController.ModeChangedListener,
109         KeyguardViewController, FoldAodAnimationController.FoldAodAnimationStatus {
110 
111     // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
112     private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
113 
114     // Delay for showing the navigation bar when the bouncer appears. This should be kept in sync
115     // with the appear animations of the PIN/pattern/password views.
116     private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320;
117 
118     // The duration to fade the nav bar content in/out when the device starts to sleep
119     private static final long NAV_BAR_CONTENT_FADE_DURATION = 125;
120 
121     // Duration of the Keyguard dismissal animation in case the user is currently locked. This is to
122     // make everything a bit slower to bridge a gap until the user is unlocked and home screen has
123     // dranw its first frame.
124     private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
125 
126     private static String TAG = "StatusBarKeyguardViewManager";
127     private static final boolean DEBUG = false;
128 
129     protected final Context mContext;
130     private final ConfigurationController mConfigurationController;
131     private final NavigationModeController mNavigationModeController;
132     private final NotificationShadeWindowController mNotificationShadeWindowController;
133     private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
134     private final DreamOverlayStateController mDreamOverlayStateController;
135     @Nullable
136     private final FoldAodAnimationController mFoldAodAnimationController;
137     private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
138     private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
139     private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
140     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
141     private final BouncerView mPrimaryBouncerView;
142     private final Lazy<ShadeController> mShadeController;
143 
144     // Local cache of expansion events, to avoid duplicates
145     private float mFraction = -1f;
146     private boolean mTracking = false;
147 
148     private final PrimaryBouncerExpansionCallback mExpansionCallback =
149             new PrimaryBouncerExpansionCallback() {
150             private boolean mPrimaryBouncerAnimating;
151 
152             @Override
153             public void onFullyShown() {
154                 mPrimaryBouncerAnimating = false;
155                 updateStates();
156             }
157 
158             @Override
159             public void onStartingToHide() {
160                 mPrimaryBouncerAnimating = true;
161                 updateStates();
162             }
163 
164             @Override
165             public void onStartingToShow() {
166                 mPrimaryBouncerAnimating = true;
167                 updateStates();
168             }
169 
170             @Override
171             public void onFullyHidden() {
172                 mPrimaryBouncerAnimating = false;
173                 updateStates();
174             }
175 
176             @Override
177             public void onExpansionChanged(float expansion) {
178                 if (mPrimaryBouncerAnimating) {
179                     mCentralSurfaces.setPrimaryBouncerHiddenFraction(expansion);
180                 }
181             }
182 
183             @Override
184             public void onVisibilityChanged(boolean isVisible) {
185                 mCentralSurfaces.setBouncerShowingOverDream(
186                         isVisible && mDreamOverlayStateController.isOverlayActive());
187 
188                 if (!isVisible) {
189                     mCentralSurfaces.setPrimaryBouncerHiddenFraction(EXPANSION_HIDDEN);
190                 }
191 
192                 /* Register predictive back callback when keyguard becomes visible, and unregister
193                 when it's hidden. */
194                 if (isVisible) {
195                     registerBackCallback();
196                 } else {
197                     unregisterBackCallback();
198                 }
199             }
200     };
201 
202     private final OnBackAnimationCallback mOnBackInvokedCallback = new OnBackAnimationCallback() {
203         @Override
204         public void onBackInvoked() {
205             if (DEBUG) {
206                 Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
207             }
208             onBackPressed();
209             if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
210                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackInvoked();
211             }
212         }
213 
214         @Override
215         public void onBackProgressed(BackEvent event) {
216             if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
217                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackProgressed(event);
218             }
219         }
220 
221         @Override
222         public void onBackCancelled() {
223             if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
224                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackCancelled();
225             }
226         }
227 
228         @Override
229         public void onBackStarted(BackEvent event) {
230             if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
231                 mPrimaryBouncerView.getDelegate().getBackCallback().onBackStarted(event);
232             }
233         }
234     };
235     private boolean mIsBackCallbackRegistered = false;
236 
237     private final DockManager.DockEventListener mDockEventListener =
238             new DockManager.DockEventListener() {
239                 @Override
240                 public void onEvent(int event) {
241                     boolean isDocked = mDockManager.isDocked();
242             if (isDocked == mIsDocked) {
243                 return;
244             }
245             mIsDocked = isDocked;
246             updateStates();
247         }
248     };
249 
250     protected LockPatternUtils mLockPatternUtils;
251     protected ViewMediatorCallback mViewMediatorCallback;
252     @Nullable protected CentralSurfaces mCentralSurfaces;
253     private NotificationPanelViewController mNotificationPanelViewController;
254     private BiometricUnlockController mBiometricUnlockController;
255     private boolean mCentralSurfacesRegistered;
256 
257     private View mNotificationContainer;
258 
259     protected boolean mRemoteInputActive;
260     private boolean mGlobalActionsVisible = false;
261     private boolean mLastGlobalActionsVisible = false;
262     private boolean mDozing;
263     private boolean mPulsing;
264     private boolean mGesturalNav;
265     private boolean mIsDocked;
266     private boolean mScreenOffAnimationPlaying;
267 
268     protected boolean mFirstUpdate = true;
269     protected boolean mLastShowing;
270     protected boolean mLastOccluded;
271     private boolean mLastPrimaryBouncerShowing;
272     private boolean mLastPrimaryBouncerIsOrWillBeShowing;
273     private boolean mLastBouncerDismissible;
274     protected boolean mLastRemoteInputActive;
275     private boolean mLastDozing;
276     private boolean mLastGesturalNav;
277     private boolean mLastIsDocked;
278     private boolean mLastPulsing;
279     private int mLastBiometricMode;
280     private boolean mLastScreenOffAnimationPlaying;
281     private float mQsExpansion;
282     private boolean mAlternateBouncerReceivedDownTouch = false;
283     final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
284     private boolean mIsModernAlternateBouncerEnabled;
285     private boolean mIsBackAnimationEnabled;
286 
287     private OnDismissAction mAfterKeyguardGoneAction;
288     private Runnable mKeyguardGoneCancelAction;
289     private boolean mDismissActionWillAnimateOnKeyguard;
290     private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
291 
292     // Dismiss action to be launched when we stop dozing or the keyguard is gone.
293     private DismissWithActionRequest mPendingWakeupAction;
294     private final KeyguardStateController mKeyguardStateController;
295     private final NotificationMediaManager mMediaManager;
296     private final SysuiStatusBarStateController mStatusBarStateController;
297     private final DockManager mDockManager;
298     private final KeyguardUpdateMonitor mKeyguardUpdateManager;
299     private final LatencyTracker mLatencyTracker;
300     private final KeyguardSecurityModel mKeyguardSecurityModel;
301     @Nullable private KeyguardBypassController mBypassController;
302     @Nullable private OccludingAppBiometricUI mOccludingAppBiometricUI;
303 
304     @Nullable private TaskbarDelegate mTaskbarDelegate;
305     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
306             new KeyguardUpdateMonitorCallback() {
307         @Override
308         public void onEmergencyCallAction() {
309             // Since we won't get a setOccluded call we have to reset the view manually such that
310             // the bouncer goes away.
311             if (mKeyguardStateController.isOccluded()) {
312                 reset(true /* hideBouncerWhenShowing */);
313             }
314         }
315     };
316 
317     @Inject
StatusBarKeyguardViewManager( Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils, SysuiStatusBarStateController sysuiStatusBarStateController, ConfigurationController configurationController, KeyguardUpdateMonitor keyguardUpdateMonitor, DreamOverlayStateController dreamOverlayStateController, NavigationModeController navigationModeController, DockManager dockManager, NotificationShadeWindowController notificationShadeWindowController, KeyguardStateController keyguardStateController, NotificationMediaManager notificationMediaManager, KeyguardMessageAreaController.Factory keyguardMessageAreaFactory, Optional<SysUIUnfoldComponent> sysUIUnfoldComponent, Lazy<ShadeController> shadeController, LatencyTracker latencyTracker, KeyguardSecurityModel keyguardSecurityModel, FeatureFlags featureFlags, PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor, PrimaryBouncerInteractor primaryBouncerInteractor, BouncerView primaryBouncerView, AlternateBouncerInteractor alternateBouncerInteractor)318     public StatusBarKeyguardViewManager(
319             Context context,
320             ViewMediatorCallback callback,
321             LockPatternUtils lockPatternUtils,
322             SysuiStatusBarStateController sysuiStatusBarStateController,
323             ConfigurationController configurationController,
324             KeyguardUpdateMonitor keyguardUpdateMonitor,
325             DreamOverlayStateController dreamOverlayStateController,
326             NavigationModeController navigationModeController,
327             DockManager dockManager,
328             NotificationShadeWindowController notificationShadeWindowController,
329             KeyguardStateController keyguardStateController,
330             NotificationMediaManager notificationMediaManager,
331             KeyguardMessageAreaController.Factory keyguardMessageAreaFactory,
332             Optional<SysUIUnfoldComponent> sysUIUnfoldComponent,
333             Lazy<ShadeController> shadeController,
334             LatencyTracker latencyTracker,
335             KeyguardSecurityModel keyguardSecurityModel,
336             FeatureFlags featureFlags,
337             PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,
338             PrimaryBouncerInteractor primaryBouncerInteractor,
339             BouncerView primaryBouncerView,
340             AlternateBouncerInteractor alternateBouncerInteractor) {
341         mContext = context;
342         mViewMediatorCallback = callback;
343         mLockPatternUtils = lockPatternUtils;
344         mConfigurationController = configurationController;
345         mNavigationModeController = navigationModeController;
346         mNotificationShadeWindowController = notificationShadeWindowController;
347         mDreamOverlayStateController = dreamOverlayStateController;
348         mKeyguardStateController = keyguardStateController;
349         mMediaManager = notificationMediaManager;
350         mKeyguardUpdateManager = keyguardUpdateMonitor;
351         mStatusBarStateController = sysuiStatusBarStateController;
352         mDockManager = dockManager;
353         mKeyguardMessageAreaFactory = keyguardMessageAreaFactory;
354         mShadeController = shadeController;
355         mLatencyTracker = latencyTracker;
356         mKeyguardSecurityModel = keyguardSecurityModel;
357         mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor;
358         mPrimaryBouncerInteractor = primaryBouncerInteractor;
359         mPrimaryBouncerView = primaryBouncerView;
360         mFoldAodAnimationController = sysUIUnfoldComponent
361                 .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
362         mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
363         mAlternateBouncerInteractor = alternateBouncerInteractor;
364         mIsBackAnimationEnabled =
365                 featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM);
366     }
367 
368     @Override
registerCentralSurfaces(CentralSurfaces centralSurfaces, NotificationPanelViewController notificationPanelViewController, ShadeExpansionStateManager shadeExpansionStateManager, BiometricUnlockController biometricUnlockController, View notificationContainer, KeyguardBypassController bypassController)369     public void registerCentralSurfaces(CentralSurfaces centralSurfaces,
370             NotificationPanelViewController notificationPanelViewController,
371             ShadeExpansionStateManager shadeExpansionStateManager,
372             BiometricUnlockController biometricUnlockController,
373             View notificationContainer,
374             KeyguardBypassController bypassController) {
375         mCentralSurfaces = centralSurfaces;
376         mBiometricUnlockController = biometricUnlockController;
377 
378         ViewGroup container = mCentralSurfaces.getBouncerContainer();
379         mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback);
380         mNotificationPanelViewController = notificationPanelViewController;
381         if (shadeExpansionStateManager != null) {
382             shadeExpansionStateManager.addExpansionListener(this);
383         }
384         mBypassController = bypassController;
385         mNotificationContainer = notificationContainer;
386         mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create(
387                 centralSurfaces.getKeyguardMessageArea());
388         mCentralSurfacesRegistered = true;
389 
390         registerListeners();
391     }
392 
393     /**
394      * Sets the given legacy alternate bouncer to null if it's the current alternate bouncer. Else,
395      * does nothing. Only used if modern alternate bouncer is NOT enabled.
396      */
removeLegacyAlternateBouncer( @onNull LegacyAlternateBouncer alternateBouncerLegacy)397     public void removeLegacyAlternateBouncer(
398             @NonNull LegacyAlternateBouncer alternateBouncerLegacy) {
399         if (!mIsModernAlternateBouncerEnabled) {
400             if (Objects.equals(mAlternateBouncerInteractor.getLegacyAlternateBouncer(),
401                     alternateBouncerLegacy)) {
402                 mAlternateBouncerInteractor.setLegacyAlternateBouncer(null);
403                 hideAlternateBouncer(true);
404             }
405         }
406     }
407 
408     /**
409      * Sets a new legacy alternate bouncer. Only used if modern alternate bouncer is NOT enabled.
410      */
setLegacyAlternateBouncer(@onNull LegacyAlternateBouncer alternateBouncerLegacy)411     public void setLegacyAlternateBouncer(@NonNull LegacyAlternateBouncer alternateBouncerLegacy) {
412         if (!mIsModernAlternateBouncerEnabled) {
413             if (!Objects.equals(mAlternateBouncerInteractor.getLegacyAlternateBouncer(),
414                     alternateBouncerLegacy)) {
415                 mAlternateBouncerInteractor.setLegacyAlternateBouncer(alternateBouncerLegacy);
416                 hideAlternateBouncer(true);
417             }
418         }
419 
420     }
421 
422 
423     /**
424      * Sets the given OccludingAppBiometricUI to null if it's the current auth interceptor. Else,
425      * does nothing.
426      */
removeOccludingAppBiometricUI(@onNull OccludingAppBiometricUI biometricUI)427     public void removeOccludingAppBiometricUI(@NonNull OccludingAppBiometricUI biometricUI) {
428         if (Objects.equals(mOccludingAppBiometricUI, biometricUI)) {
429             mOccludingAppBiometricUI = null;
430         }
431     }
432 
433     /**
434      * Sets a new OccludingAppBiometricUI.
435      */
setOccludingAppBiometricUI(@onNull OccludingAppBiometricUI biometricUI)436     public void setOccludingAppBiometricUI(@NonNull OccludingAppBiometricUI biometricUI) {
437         if (!Objects.equals(mOccludingAppBiometricUI, biometricUI)) {
438             mOccludingAppBiometricUI = biometricUI;
439         }
440     }
441 
registerListeners()442     private void registerListeners() {
443         mKeyguardUpdateManager.registerCallback(mUpdateMonitorCallback);
444         mStatusBarStateController.addCallback(this);
445         mConfigurationController.addCallback(this);
446         mGesturalNav = QuickStepContract.isGesturalMode(
447                 mNavigationModeController.addListener(this));
448         if (mFoldAodAnimationController != null) {
449             mFoldAodAnimationController.addCallback(this);
450         }
451         if (mDockManager != null) {
452             mDockManager.addListener(mDockEventListener);
453             mIsDocked = mDockManager.isDocked();
454         }
455     }
456 
457     /** Register a callback, to be invoked by the Predictive Back system. */
registerBackCallback()458     private void registerBackCallback() {
459         if (!mIsBackCallbackRegistered) {
460             ViewRootImpl viewRoot = getViewRootImpl();
461             if (viewRoot != null) {
462                 viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
463                         OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback);
464                 mIsBackCallbackRegistered = true;
465             } else {
466                 if (DEBUG) {
467                     Log.d(TAG, "view root was null, could not register back callback");
468                 }
469             }
470         } else {
471             if (DEBUG) {
472                 Log.d(TAG, "prevented registering back callback twice");
473             }
474         }
475     }
476 
477     /** Unregister the callback formerly registered with the Predictive Back system. */
unregisterBackCallback()478     private void unregisterBackCallback() {
479         if (mIsBackCallbackRegistered) {
480             ViewRootImpl viewRoot = getViewRootImpl();
481             if (viewRoot != null) {
482                 viewRoot.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
483                         mOnBackInvokedCallback);
484                 mIsBackCallbackRegistered = false;
485             } else {
486                 if (DEBUG) {
487                     Log.d(TAG, "view root was null, could not unregister back callback");
488                 }
489             }
490         } else {
491             if (DEBUG) {
492                 Log.d(TAG, "prevented unregistering back callback twice");
493             }
494         }
495     }
496 
shouldPlayBackAnimation()497     private boolean shouldPlayBackAnimation() {
498         // Suppress back animation when bouncer shouldn't be dismissed on back invocation.
499         return !needsFullscreenBouncer() && mIsBackAnimationEnabled;
500     }
501 
502     @Override
onDensityOrFontScaleChanged()503     public void onDensityOrFontScaleChanged() {
504         hideBouncer(true /* destroyView */);
505     }
506 
beginShowingBouncer(ShadeExpansionChangeEvent event)507     private boolean beginShowingBouncer(ShadeExpansionChangeEvent event) {
508         // Avoid having the shade and the bouncer open at the same time over a dream.
509         final boolean hideBouncerOverDream =
510                 mDreamOverlayStateController.isOverlayActive()
511                         && (mNotificationPanelViewController.isExpanded()
512                         || mNotificationPanelViewController.isExpanding());
513 
514         final boolean isUserTrackingStarted =
515                 event.getFraction() != EXPANSION_HIDDEN && event.getTracking();
516 
517         return mKeyguardStateController.isShowing()
518                 && !primaryBouncerIsOrWillBeShowing()
519                 && isUserTrackingStarted
520                 && !hideBouncerOverDream
521                 && !mKeyguardStateController.isOccluded()
522                 && !mKeyguardStateController.canDismissLockScreen()
523                 && !bouncerIsAnimatingAway()
524                 && !mNotificationPanelViewController.isUnlockHintRunning()
525                 && !(mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED);
526     }
527 
528     @Override
onPanelExpansionChanged(ShadeExpansionChangeEvent event)529     public void onPanelExpansionChanged(ShadeExpansionChangeEvent event) {
530         float fraction = event.getFraction();
531         boolean tracking = event.getTracking();
532 
533         if (mFraction == fraction && mTracking == tracking) {
534             // Ignore duplicate events, as they will cause confusion with bouncer expansion
535             return;
536         }
537         mFraction = fraction;
538         mTracking = tracking;
539 
540         /*
541          * The bouncer may have received a call to show(), or the following will infer it from
542          * device state and touch handling. The bouncer MUST have been notified that it is about to
543          * show if any subsequent events are to be handled.
544          */
545         if (beginShowingBouncer(event)) {
546             mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
547         }
548 
549         if (!primaryBouncerIsOrWillBeShowing()) {
550             return;
551         }
552 
553         if (mKeyguardStateController.isShowing()) {
554             mPrimaryBouncerInteractor.setPanelExpansion(fraction);
555         } else {
556             mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN);
557         }
558     }
559 
560     /**
561      * Update the global actions visibility state in order to show the navBar when active.
562      */
setGlobalActionsVisible(boolean isVisible)563     public void setGlobalActionsVisible(boolean isVisible) {
564         mGlobalActionsVisible = isVisible;
565         updateStates();
566     }
567 
setTaskbarDelegate(TaskbarDelegate taskbarDelegate)568     public void setTaskbarDelegate(TaskbarDelegate taskbarDelegate) {
569         mTaskbarDelegate = taskbarDelegate;
570     }
571 
572     /**
573      * Show the keyguard.  Will handle creating and attaching to the view manager
574      * lazily.
575      */
576     @Override
show(Bundle options)577     public void show(Bundle options) {
578         Trace.beginSection("StatusBarKeyguardViewManager#show");
579         mNotificationShadeWindowController.setKeyguardShowing(true);
580         mKeyguardStateController.notifyKeyguardState(true,
581                 mKeyguardStateController.isOccluded());
582         reset(true /* hideBouncerWhenShowing */);
583         SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
584                 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
585         Trace.endSection();
586     }
587 
588     /**
589      * Shows the notification keyguard or the bouncer depending on
590      * {@link #needsFullscreenBouncer()}.
591      */
showBouncerOrKeyguard(boolean hideBouncerWhenShowing)592     protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
593         if (needsFullscreenBouncer() && !mDozing) {
594             // The keyguard might be showing (already). So we need to hide it.
595             mCentralSurfaces.hideKeyguard();
596             mPrimaryBouncerInteractor.show(true);
597         } else {
598             mCentralSurfaces.showKeyguard();
599             if (hideBouncerWhenShowing) {
600                 hideBouncer(false /* destroyView */);
601             }
602         }
603         updateStates();
604     }
605 
606     /**
607      *
608      * If possible, shows the alternate bouncer. Else, shows the primary (pin/pattern/password)
609      * bouncer.
610      * @param scrimmed true when the primary bouncer should show scrimmed,
611      *                 false when the user will be dragging it and translation should be deferred
612      *                 {@see KeyguardBouncer#show(boolean, boolean)}
613      */
showBouncer(boolean scrimmed)614     public void showBouncer(boolean scrimmed) {
615         if (!mAlternateBouncerInteractor.show()) {
616             showPrimaryBouncer(scrimmed);
617         } else {
618             updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
619         }
620     }
621 
622     /**
623      * Hides the input bouncer (pin/password/pattern).
624      */
625     @VisibleForTesting
hideBouncer(boolean destroyView)626     void hideBouncer(boolean destroyView) {
627         mPrimaryBouncerInteractor.hide();
628         if (mKeyguardStateController.isShowing()) {
629             // If we were showing the bouncer and then aborting, we need to also clear out any
630             // potential actions unless we actually unlocked.
631             cancelPostAuthActions();
632         }
633         cancelPendingWakeupAction();
634     }
635 
636     /**
637      * Shows the primary bouncer - the pin/pattern/password challenge on the lock screen.
638      *
639      * @param scrimmed true when the bouncer should show scrimmed, false when the user will be
640      * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
641      */
showPrimaryBouncer(boolean scrimmed)642     public void showPrimaryBouncer(boolean scrimmed) {
643         hideAlternateBouncer(false);
644         if (mKeyguardStateController.isShowing() && !isBouncerShowing()) {
645             mPrimaryBouncerInteractor.show(scrimmed);
646         }
647         updateStates();
648     }
649 
dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone)650     public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
651             boolean afterKeyguardGone) {
652         dismissWithAction(r, cancelAction, afterKeyguardGone, null /* message */);
653     }
654 
dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone, String message)655     public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
656             boolean afterKeyguardGone, String message) {
657         if (mKeyguardStateController.isShowing()) {
658             try {
659                 Trace.beginSection("StatusBarKeyguardViewManager#dismissWithAction");
660                 cancelPendingWakeupAction();
661                 // If we're dozing, this needs to be delayed until after we wake up - unless we're
662                 // wake-and-unlocking, because there dozing will last until the end of the
663                 // transition.
664                 if (mDozing && !isWakeAndUnlocking()) {
665                     mPendingWakeupAction = new DismissWithActionRequest(
666                             r, cancelAction, afterKeyguardGone, message);
667                     return;
668                 }
669 
670                 mAfterKeyguardGoneAction = r;
671                 mKeyguardGoneCancelAction = cancelAction;
672                 mDismissActionWillAnimateOnKeyguard = r != null && r.willRunAnimationOnKeyguard();
673 
674                 // If there is an alternate auth interceptor (like the UDFPS), show that one
675                 // instead of the bouncer.
676                 if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) {
677                     if (!afterKeyguardGone) {
678                         mPrimaryBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction,
679                                 mKeyguardGoneCancelAction);
680                         mAfterKeyguardGoneAction = null;
681                         mKeyguardGoneCancelAction = null;
682                     }
683 
684                     updateAlternateBouncerShowing(mAlternateBouncerInteractor.show());
685                     return;
686                 }
687 
688                 if (afterKeyguardGone) {
689                     // we'll handle the dismiss action after keyguard is gone, so just show the
690                     // bouncer
691                     mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
692                 } else {
693                     // after authentication success, run dismiss action with the option to defer
694                     // hiding the keyguard based on the return value of the OnDismissAction
695                     mPrimaryBouncerInteractor.setDismissAction(
696                             mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
697                     mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
698                     // bouncer will handle the dismiss action, so we no longer need to track it here
699                     mAfterKeyguardGoneAction = null;
700                     mKeyguardGoneCancelAction = null;
701                 }
702             } finally {
703                 Trace.endSection();
704             }
705         }
706         updateStates();
707     }
708 
isWakeAndUnlocking()709     private boolean isWakeAndUnlocking() {
710         int mode = mBiometricUnlockController.getMode();
711         return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING;
712     }
713 
714     /**
715      * Adds a {@param runnable} to be executed after Keyguard is gone.
716      */
addAfterKeyguardGoneRunnable(Runnable runnable)717     public void addAfterKeyguardGoneRunnable(Runnable runnable) {
718         mAfterKeyguardGoneRunnables.add(runnable);
719     }
720 
721     @Override
reset(boolean hideBouncerWhenShowing)722     public void reset(boolean hideBouncerWhenShowing) {
723         if (mKeyguardStateController.isShowing()) {
724             final boolean isOccluded = mKeyguardStateController.isOccluded();
725             // Hide quick settings.
726             mNotificationPanelViewController.resetViews(/* animate= */ !isOccluded);
727             // Hide bouncer and quick-quick settings.
728             if (isOccluded && !mDozing) {
729                 mCentralSurfaces.hideKeyguard();
730                 if (hideBouncerWhenShowing || needsFullscreenBouncer()) {
731                     hideBouncer(false /* destroyView */);
732                 }
733             } else {
734                 showBouncerOrKeyguard(hideBouncerWhenShowing);
735             }
736             if (hideBouncerWhenShowing) {
737                 hideAlternateBouncer(true);
738             }
739             mKeyguardUpdateManager.sendKeyguardReset();
740             updateStates();
741         }
742     }
743 
744     @Override
hideAlternateBouncer(boolean updateScrim)745     public void hideAlternateBouncer(boolean updateScrim) {
746         updateAlternateBouncerShowing(mAlternateBouncerInteractor.hide() && updateScrim);
747     }
748 
updateAlternateBouncerShowing(boolean updateScrim)749     private void updateAlternateBouncerShowing(boolean updateScrim) {
750         if (!mCentralSurfacesRegistered) {
751             // if CentralSurfaces hasn't been registered yet, then the controllers below haven't
752             // been initialized yet so there's no need to attempt to forward them events.
753             return;
754         }
755 
756         final boolean isShowingAlternateBouncer = mAlternateBouncerInteractor.isVisibleState();
757         if (mKeyguardMessageAreaController != null) {
758             mKeyguardMessageAreaController.setIsVisible(isShowingAlternateBouncer);
759             mKeyguardMessageAreaController.setMessage("");
760         }
761         mBypassController.setAltBouncerShowing(isShowingAlternateBouncer);
762         mKeyguardUpdateManager.setAlternateBouncerShowing(isShowingAlternateBouncer);
763 
764         if (updateScrim) {
765             mCentralSurfaces.updateScrimController();
766         }
767     }
768 
769     @Override
onStartedWakingUp()770     public void onStartedWakingUp() {
771         mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController()
772                 .setAnimationsDisabled(false);
773         NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView();
774         if (navBarView != null) {
775             navBarView.forEachView(view ->
776                     view.animate()
777                             .alpha(1f)
778                             .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
779                             .start());
780         }
781     }
782 
783     @Override
onStartedGoingToSleep()784     public void onStartedGoingToSleep() {
785         mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController()
786                 .setAnimationsDisabled(true);
787         NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView();
788         if (navBarView != null) {
789             navBarView.forEachView(view ->
790                     view.animate()
791                             .alpha(0f)
792                             .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
793                             .start());
794         }
795     }
796 
797     @Override
onFinishedGoingToSleep()798     public void onFinishedGoingToSleep() {
799         mPrimaryBouncerInteractor.hide();
800     }
801 
802     @Override
onRemoteInputActive(boolean active)803     public void onRemoteInputActive(boolean active) {
804         mRemoteInputActive = active;
805         updateStates();
806     }
807 
setDozing(boolean dozing)808     private void setDozing(boolean dozing) {
809         if (mDozing != dozing) {
810             mDozing = dozing;
811             if (dozing || needsFullscreenBouncer()
812                     || mKeyguardStateController.isOccluded()) {
813                 reset(dozing /* hideBouncerWhenShowing */);
814             }
815             updateStates();
816 
817             if (!dozing) {
818                 launchPendingWakeupAction();
819             }
820         }
821     }
822 
823     /**
824      * If {@link CentralSurfaces} is pulsing.
825      */
setPulsing(boolean pulsing)826     public void setPulsing(boolean pulsing) {
827         if (mPulsing != pulsing) {
828             mPulsing = pulsing;
829             updateStates();
830         }
831     }
832 
833     @Override
setNeedsInput(boolean needsInput)834     public void setNeedsInput(boolean needsInput) {
835         mNotificationShadeWindowController.setKeyguardNeedsInput(needsInput);
836     }
837 
838     @Override
isUnlockWithWallpaper()839     public boolean isUnlockWithWallpaper() {
840         return mNotificationShadeWindowController.isShowingWallpaper();
841     }
842 
843     @Override
setOccluded(boolean occluded, boolean animate)844     public void setOccluded(boolean occluded, boolean animate) {
845         final boolean wasOccluded = mKeyguardStateController.isOccluded();
846         final boolean isOccluding = !wasOccluded && occluded;
847         final boolean isUnOccluding = wasOccluded  && !occluded;
848         mKeyguardStateController.notifyKeyguardState(
849                 mKeyguardStateController.isShowing(), occluded);
850         updateStates();
851         final boolean isShowing = mKeyguardStateController.isShowing();
852         final boolean isOccluded = mKeyguardStateController.isOccluded();
853 
854         if (isShowing && isOccluding) {
855             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
856                     SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED);
857             if (mCentralSurfaces.isLaunchingActivityOverLockscreen()) {
858                 // When isLaunchingActivityOverLockscreen() is true, we know for sure that the post
859                 // collapse runnables will be run.
860                 mShadeController.get().addPostCollapseAction(() -> {
861                     mNotificationShadeWindowController.setKeyguardOccluded(isOccluded);
862                     reset(true /* hideBouncerWhenShowing */);
863                 });
864                 return;
865             }
866         } else if (isShowing && isUnOccluding) {
867             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
868                     SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
869         }
870         if (isShowing) {
871             mMediaManager.updateMediaMetaData(false, animate && !isOccluded);
872         }
873         mNotificationShadeWindowController.setKeyguardOccluded(isOccluded);
874 
875         // setDozing(false) will call reset once we stop dozing. Also, if we're going away, there's
876         // no need to reset the keyguard views as we'll be gone shortly. Resetting now could cause
877         // unexpected visible behavior if the keyguard is still visible as we're animating unlocked.
878         if (!mDozing && !mKeyguardStateController.isKeyguardGoingAway()) {
879             // If Keyguard is reshown, don't hide the bouncer as it might just have been requested
880             // by a FLAG_DISMISS_KEYGUARD_ACTIVITY.
881             reset(isOccluding /* hideBouncerWhenShowing*/);
882         }
883     }
884 
885     @Override
startPreHideAnimation(Runnable finishRunnable)886     public void startPreHideAnimation(Runnable finishRunnable) {
887         if (primaryBouncerIsShowing()) {
888             mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable);
889             mNotificationPanelViewController.startBouncerPreHideAnimation();
890 
891             // We update the state (which will show the keyguard) only if an animation will run on
892             // the keyguard. If there is no animation, we wait before updating the state so that we
893             // go directly from bouncer to launcher/app.
894             if (mDismissActionWillAnimateOnKeyguard) {
895                 updateStates();
896             }
897         } else if (finishRunnable != null) {
898             finishRunnable.run();
899         }
900         mNotificationPanelViewController.blockExpansionForCurrentTouch();
901     }
902 
903     @Override
blockPanelExpansionFromCurrentTouch()904     public void blockPanelExpansionFromCurrentTouch() {
905         mNotificationPanelViewController.blockExpansionForCurrentTouch();
906     }
907 
908     @Override
hide(long startTime, long fadeoutDuration)909     public void hide(long startTime, long fadeoutDuration) {
910         Trace.beginSection("StatusBarKeyguardViewManager#hide");
911         mKeyguardStateController.notifyKeyguardState(false,
912                 mKeyguardStateController.isOccluded());
913         launchPendingWakeupAction();
914 
915         if (mKeyguardUpdateManager.needsSlowUnlockTransition()) {
916             fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
917         }
918         long uptimeMillis = SystemClock.uptimeMillis();
919         long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);
920 
921         if (mKeyguardStateController.isFlingingToDismissKeyguard()) {
922             final boolean wasFlingingToDismissKeyguard =
923                     mKeyguardStateController.isFlingingToDismissKeyguard();
924             mCentralSurfaces.fadeKeyguardAfterLaunchTransition(new Runnable() {
925                 @Override
926                 public void run() {
927                     mNotificationShadeWindowController.setKeyguardShowing(false);
928                     mNotificationShadeWindowController.setKeyguardFadingAway(true);
929                     hideBouncer(true /* destroyView */);
930                     updateStates();
931                 }
932             }, /* endRunnable */ new Runnable() {
933                 @Override
934                 public void run() {
935                     mCentralSurfaces.hideKeyguard();
936                     mNotificationShadeWindowController.setKeyguardFadingAway(false);
937 
938                     if (wasFlingingToDismissKeyguard) {
939                         mCentralSurfaces.finishKeyguardFadingAway();
940                     }
941 
942                     mViewMediatorCallback.keyguardGone();
943                     executeAfterKeyguardGoneAction();
944                 }
945             }, /* cancelRunnable */ new Runnable() {
946                 @Override
947                 public void run() {
948                     mNotificationShadeWindowController.setKeyguardFadingAway(false);
949                     if (wasFlingingToDismissKeyguard) {
950                         mCentralSurfaces.finishKeyguardFadingAway();
951                     }
952                     cancelPostAuthActions();
953                 }
954             });
955         } else {
956             executeAfterKeyguardGoneAction();
957             mCentralSurfaces.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
958             mBiometricUnlockController.startKeyguardFadingAway();
959             hideBouncer(true /* destroyView */);
960 
961             boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
962             if (!staying) {
963                 mNotificationShadeWindowController.setKeyguardFadingAway(true);
964                 mCentralSurfaces.hideKeyguard();
965                 // hide() will happen asynchronously and might arrive after the scrims
966                 // were already hidden, this means that the transition callback won't
967                 // be triggered anymore and StatusBarWindowController will be forever in
968                 // the fadingAway state.
969                 mCentralSurfaces.updateScrimController();
970                 wakeAndUnlockDejank();
971             } else {
972                 mCentralSurfaces.hideKeyguard();
973                 mCentralSurfaces.finishKeyguardFadingAway();
974                 mBiometricUnlockController.finishKeyguardFadingAway();
975             }
976 
977             updateStates();
978             mNotificationShadeWindowController.setKeyguardShowing(false);
979             mViewMediatorCallback.keyguardGone();
980         }
981         SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
982                 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
983         Trace.endSection();
984     }
985 
986     @Override
onNavigationModeChanged(int mode)987     public void onNavigationModeChanged(int mode) {
988         boolean gesturalNav = QuickStepContract.isGesturalMode(mode);
989         if (gesturalNav != mGesturalNav) {
990             mGesturalNav = gesturalNav;
991             updateStates();
992         }
993     }
994 
onThemeChanged()995     public void onThemeChanged() {
996         updateResources();
997     }
998 
onKeyguardFadedAway()999     public void onKeyguardFadedAway() {
1000         mNotificationContainer.postDelayed(() -> mNotificationShadeWindowController
1001                         .setKeyguardFadingAway(false), 100);
1002         mNotificationPanelViewController.resetViewAlphas();
1003         mCentralSurfaces.finishKeyguardFadingAway();
1004         mBiometricUnlockController.finishKeyguardFadingAway();
1005         WindowManagerGlobal.getInstance().trimMemory(
1006                 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
1007 
1008     }
1009 
wakeAndUnlockDejank()1010     private void wakeAndUnlockDejank() {
1011         if (mBiometricUnlockController.isWakeAndUnlock() && mLatencyTracker.isEnabled()) {
1012             BiometricSourceType type = mBiometricUnlockController.getBiometricType();
1013             mLatencyTracker.onActionEnd(type == BiometricSourceType.FACE
1014                             ? LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK
1015                             : LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
1016         }
1017     }
1018 
executeAfterKeyguardGoneAction()1019     private void executeAfterKeyguardGoneAction() {
1020         if (mAfterKeyguardGoneAction != null) {
1021             mAfterKeyguardGoneAction.onDismiss();
1022             mAfterKeyguardGoneAction = null;
1023         }
1024         mKeyguardGoneCancelAction = null;
1025         mDismissActionWillAnimateOnKeyguard = false;
1026         for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) {
1027             mAfterKeyguardGoneRunnables.get(i).run();
1028         }
1029         mAfterKeyguardGoneRunnables.clear();
1030     }
1031 
1032     @Override
dismissAndCollapse()1033     public void dismissAndCollapse() {
1034         mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, true, false, true);
1035     }
1036 
1037     /**
1038      * WARNING: This method might cause Binder calls.
1039      */
isSecure()1040     public boolean isSecure() {
1041         return mKeyguardSecurityModel.getSecurityMode(
1042                 KeyguardUpdateMonitor.getCurrentUser()) != KeyguardSecurityModel.SecurityMode.None;
1043     }
1044 
1045     /**
1046      * Returns whether a back invocation can be handled, which depends on whether the keyguard
1047      * is currently showing (which itself is derived from multiple states).
1048      *
1049      * @return whether a back press can be handled right now.
1050      */
canHandleBackPressed()1051     public boolean canHandleBackPressed() {
1052         return primaryBouncerIsShowing();
1053     }
1054 
1055     /**
1056      * Notifies this manager that the back button has been pressed.
1057      */
onBackPressed()1058     public void onBackPressed() {
1059         if (!canHandleBackPressed()) {
1060             return;
1061         }
1062 
1063         mCentralSurfaces.endAffordanceLaunch();
1064         // The second condition is for SIM card locked bouncer
1065         if (primaryBouncerIsScrimmed() && !needsFullscreenBouncer()) {
1066             hideBouncer(false);
1067             updateStates();
1068         } else {
1069             /* Non-scrimmed bouncers have a special animation tied to the expansion
1070              * of the notification panel. We decide whether to kick this animation off
1071              * by computing the hideImmediately boolean.
1072              */
1073             boolean hideImmediately = mCentralSurfaces.shouldKeyguardHideImmediately();
1074             reset(hideImmediately);
1075             if (hideImmediately) {
1076                 mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
1077             } else {
1078                 mNotificationPanelViewController.expandShadeToNotifications();
1079             }
1080         }
1081         return;
1082     }
1083 
1084     @Override
isBouncerShowing()1085     public boolean isBouncerShowing() {
1086         return primaryBouncerIsShowing() || mAlternateBouncerInteractor.isVisibleState();
1087     }
1088 
1089     @Override
primaryBouncerIsOrWillBeShowing()1090     public boolean primaryBouncerIsOrWillBeShowing() {
1091         return isBouncerShowing() || isPrimaryBouncerInTransit();
1092     }
1093 
isFullscreenBouncer()1094     public boolean isFullscreenBouncer() {
1095         return mPrimaryBouncerView.getDelegate() != null
1096                 && mPrimaryBouncerView.getDelegate().isFullScreenBouncer();
1097     }
1098 
1099     /**
1100      * Clear out any potential actions that were saved to run when the device is unlocked
1101      */
cancelPostAuthActions()1102     public void cancelPostAuthActions() {
1103         if (primaryBouncerIsOrWillBeShowing()) {
1104             return; // allow the primary bouncer to trigger saved actions
1105         }
1106         mAfterKeyguardGoneAction = null;
1107         mDismissActionWillAnimateOnKeyguard = false;
1108         if (mKeyguardGoneCancelAction != null) {
1109             mKeyguardGoneCancelAction.run();
1110             mKeyguardGoneCancelAction = null;
1111         }
1112     }
1113 
getNavBarShowDelay()1114     private long getNavBarShowDelay() {
1115         if (mKeyguardStateController.isKeyguardFadingAway()) {
1116             return mKeyguardStateController.getKeyguardFadingAwayDelay();
1117         } else if (isBouncerShowing()) {
1118             return NAV_BAR_SHOW_DELAY_BOUNCER;
1119         } else {
1120             // No longer dozing, or remote input is active. No delay.
1121             return 0;
1122         }
1123     }
1124 
1125     private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() {
1126         @Override
1127         public void run() {
1128             NavigationBarView view = mCentralSurfaces.getNavigationBarView();
1129             if (view != null) {
1130                 view.setVisibility(View.VISIBLE);
1131             }
1132             mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController()
1133                     .show(navigationBars());
1134         }
1135     };
1136 
updateStates()1137     protected void updateStates() {
1138         if (!mCentralSurfacesRegistered) {
1139             return;
1140         }
1141         boolean showing = mKeyguardStateController.isShowing();
1142         boolean occluded = mKeyguardStateController.isOccluded();
1143         boolean primaryBouncerShowing = primaryBouncerIsShowing();
1144         boolean primaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing();
1145         boolean primaryBouncerDismissible = !isFullscreenBouncer();
1146         boolean remoteInputActive = mRemoteInputActive;
1147 
1148         if ((primaryBouncerDismissible || !showing || remoteInputActive)
1149                 != (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive)
1150                 || mFirstUpdate) {
1151             if (primaryBouncerDismissible || !showing || remoteInputActive) {
1152                 mPrimaryBouncerInteractor.setBackButtonEnabled(true);
1153             } else {
1154                 mPrimaryBouncerInteractor.setBackButtonEnabled(false);
1155             }
1156         }
1157 
1158         boolean navBarVisible = isNavBarVisible();
1159         boolean lastNavBarVisible = getLastNavBarVisible();
1160         if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
1161             updateNavigationBarVisibility(navBarVisible);
1162         }
1163 
1164         boolean isPrimaryBouncerShowingChanged =
1165             primaryBouncerShowing != mLastPrimaryBouncerShowing;
1166         mLastPrimaryBouncerShowing = primaryBouncerShowing;
1167 
1168         if (isPrimaryBouncerShowingChanged || mFirstUpdate) {
1169             mNotificationShadeWindowController.setBouncerShowing(primaryBouncerShowing);
1170             mCentralSurfaces.setBouncerShowing(primaryBouncerShowing);
1171         }
1172         if (primaryBouncerIsOrWillBeShowing != mLastPrimaryBouncerIsOrWillBeShowing || mFirstUpdate
1173                 || isPrimaryBouncerShowingChanged) {
1174             mKeyguardUpdateManager.sendPrimaryBouncerChanged(primaryBouncerIsOrWillBeShowing,
1175                     primaryBouncerShowing);
1176         }
1177 
1178         mFirstUpdate = false;
1179         mLastShowing = showing;
1180         mLastGlobalActionsVisible = mGlobalActionsVisible;
1181         mLastOccluded = occluded;
1182         mLastPrimaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing;
1183         mLastBouncerDismissible = primaryBouncerDismissible;
1184         mLastRemoteInputActive = remoteInputActive;
1185         mLastDozing = mDozing;
1186         mLastPulsing = mPulsing;
1187         mLastScreenOffAnimationPlaying = mScreenOffAnimationPlaying;
1188         mLastBiometricMode = mBiometricUnlockController.getMode();
1189         mLastGesturalNav = mGesturalNav;
1190         mLastIsDocked = mIsDocked;
1191         mCentralSurfaces.onKeyguardViewManagerStatesUpdated();
1192     }
1193 
1194     /**
1195      * Updates the visibility of the nav bar window (which will cause insets changes).
1196      */
updateNavigationBarVisibility(boolean navBarVisible)1197     protected void updateNavigationBarVisibility(boolean navBarVisible) {
1198         if (mCentralSurfaces.getNavigationBarView() != null
1199                 || (mTaskbarDelegate != null && mTaskbarDelegate.isInitialized())) {
1200             if (navBarVisible) {
1201                 long delay = getNavBarShowDelay();
1202                 if (delay == 0) {
1203                     mMakeNavigationBarVisibleRunnable.run();
1204                 } else {
1205                     mNotificationContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable,
1206                             delay);
1207                 }
1208             } else {
1209                 mNotificationContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable);
1210                 mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController()
1211                         .hide(navigationBars());
1212             }
1213         }
1214     }
1215 
1216     /**
1217      * @return Whether the navigation bar should be made visible based on the current state.
1218      */
isNavBarVisible()1219     public boolean isNavBarVisible() {
1220         boolean isWakeAndUnlockPulsing = mBiometricUnlockController != null
1221                 && mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
1222         boolean keyguardVisible = mKeyguardStateController.isVisible();
1223         boolean hideWhileDozing = mDozing && !isWakeAndUnlockPulsing;
1224         boolean keyguardWithGestureNav = (keyguardVisible && !mDozing && !mScreenOffAnimationPlaying
1225                 || mPulsing && !mIsDocked)
1226                 && mGesturalNav;
1227         return (!keyguardVisible && !hideWhileDozing && !mScreenOffAnimationPlaying
1228                 || primaryBouncerIsShowing()
1229                 || mRemoteInputActive
1230                 || keyguardWithGestureNav
1231                 || mGlobalActionsVisible);
1232     }
1233 
1234     /**
1235      * @return Whether the navigation bar was made visible based on the last known state.
1236      */
getLastNavBarVisible()1237     protected boolean getLastNavBarVisible() {
1238         boolean keyguardShowing = mLastShowing && !mLastOccluded;
1239         boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
1240         boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing
1241                 && !mLastScreenOffAnimationPlaying || mLastPulsing && !mLastIsDocked)
1242                 && mLastGesturalNav;
1243         return (!keyguardShowing && !hideWhileDozing && !mLastScreenOffAnimationPlaying
1244                 || mLastPrimaryBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav
1245                 || mLastGlobalActionsVisible);
1246     }
1247 
shouldDismissOnMenuPressed()1248     public boolean shouldDismissOnMenuPressed() {
1249         return mPrimaryBouncerView.getDelegate() != null
1250                 && mPrimaryBouncerView.getDelegate().shouldDismissOnMenuPressed();
1251     }
1252 
interceptMediaKey(KeyEvent event)1253     public boolean interceptMediaKey(KeyEvent event) {
1254         return mPrimaryBouncerView.getDelegate() != null
1255                 && mPrimaryBouncerView.getDelegate().interceptMediaKey(event);
1256     }
1257 
1258     /**
1259      * @return true if the pre IME back event should be handled
1260      */
dispatchBackKeyEventPreIme()1261     public boolean dispatchBackKeyEventPreIme() {
1262         return mPrimaryBouncerView.getDelegate() != null
1263                 && mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme();
1264     }
1265 
readyForKeyguardDone()1266     public void readyForKeyguardDone() {
1267         mViewMediatorCallback.readyForKeyguardDone();
1268     }
1269 
1270     @Override
shouldDisableWindowAnimationsForUnlock()1271     public boolean shouldDisableWindowAnimationsForUnlock() {
1272         return false;
1273     }
1274 
1275     @Override
shouldSubtleWindowAnimationsForUnlock()1276     public boolean shouldSubtleWindowAnimationsForUnlock() {
1277         return false;
1278     }
1279 
1280     @Override
isGoingToNotificationShade()1281     public boolean isGoingToNotificationShade() {
1282         return mStatusBarStateController.leaveOpenOnKeyguardHide();
1283     }
1284 
isSecure(int userId)1285     public boolean isSecure(int userId) {
1286         return isSecure() || mLockPatternUtils.isSecure(userId);
1287     }
1288 
1289     @Override
keyguardGoingAway()1290     public void keyguardGoingAway() {
1291         mCentralSurfaces.keyguardGoingAway();
1292     }
1293 
1294     @Override
setKeyguardGoingAwayState(boolean isKeyguardGoingAway)1295     public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) {
1296         mNotificationShadeWindowController.setKeyguardGoingAway(isKeyguardGoingAway);
1297     }
1298 
1299     @Override
onCancelClicked()1300     public void onCancelClicked() {
1301         // No-op
1302     }
1303 
1304     /**
1305      * Notifies that the user has authenticated by other means than using the bouncer, for example,
1306      * fingerprint.
1307      */
notifyKeyguardAuthenticated(boolean strongAuth)1308     public void notifyKeyguardAuthenticated(boolean strongAuth) {
1309         mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
1310 
1311         if (mAlternateBouncerInteractor.isVisibleState()) {
1312             hideAlternateBouncer(false);
1313             executeAfterKeyguardGoneAction();
1314         }
1315     }
1316 
1317     /** Display security message to relevant KeyguardMessageArea. */
setKeyguardMessage(String message, ColorStateList colorState)1318     public void setKeyguardMessage(String message, ColorStateList colorState) {
1319         if (mAlternateBouncerInteractor.isVisibleState()) {
1320             if (mKeyguardMessageAreaController != null) {
1321                 mKeyguardMessageAreaController.setMessage(message);
1322             }
1323         } else {
1324             mPrimaryBouncerInteractor.showMessage(message, colorState);
1325         }
1326     }
1327 
1328     @Override
getViewRootImpl()1329     public ViewRootImpl getViewRootImpl() {
1330         ViewGroup viewGroup = mNotificationShadeWindowController.getNotificationShadeView();
1331         if (viewGroup != null) {
1332             return viewGroup.getViewRootImpl();
1333         } else {
1334             if (DEBUG) {
1335                 Log.d(TAG, "ViewGroup was null, cannot get ViewRootImpl");
1336             }
1337             return null;
1338         }
1339     }
1340 
launchPendingWakeupAction()1341     public void launchPendingWakeupAction() {
1342         DismissWithActionRequest request = mPendingWakeupAction;
1343         mPendingWakeupAction = null;
1344         if (request != null) {
1345             if (mKeyguardStateController.isShowing()) {
1346                 dismissWithAction(request.dismissAction, request.cancelAction,
1347                         request.afterKeyguardGone, request.message);
1348             } else if (request.dismissAction != null) {
1349                 request.dismissAction.onDismiss();
1350             }
1351         }
1352     }
1353 
cancelPendingWakeupAction()1354     public void cancelPendingWakeupAction() {
1355         DismissWithActionRequest request = mPendingWakeupAction;
1356         mPendingWakeupAction = null;
1357         if (request != null && request.cancelAction != null) {
1358             request.cancelAction.run();
1359         }
1360     }
1361 
1362     /**
1363      * Whether the primary bouncer requires scrimming.
1364      */
primaryBouncerNeedsScrimming()1365     public boolean primaryBouncerNeedsScrimming() {
1366         // When a dream overlay is active, scrimming will cause any expansion to immediately expand.
1367         return (mKeyguardStateController.isOccluded()
1368                 && !mDreamOverlayStateController.isOverlayActive())
1369                 || primaryBouncerWillDismissWithAction()
1370                 || (primaryBouncerIsShowing() && primaryBouncerIsScrimmed())
1371                 || isFullscreenBouncer();
1372     }
1373 
1374     /**
1375      * Apply keyguard configuration from the currently active resources. This can be called when the
1376      * device configuration changes, to re-apply some resources that are qualified on the device
1377      * configuration.
1378      */
updateResources()1379     public void updateResources() {
1380         mPrimaryBouncerInteractor.updateResources();
1381     }
1382 
dump(PrintWriter pw)1383     public void dump(PrintWriter pw) {
1384         pw.println("StatusBarKeyguardViewManager:");
1385         pw.println("  mIsModernAlternateBouncerEnabled: " + mIsModernAlternateBouncerEnabled);
1386         pw.println("  mRemoteInputActive: " + mRemoteInputActive);
1387         pw.println("  mDozing: " + mDozing);
1388         pw.println("  mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction);
1389         pw.println("  mAfterKeyguardGoneRunnables: " + mAfterKeyguardGoneRunnables);
1390         pw.println("  mPendingWakeupAction: " + mPendingWakeupAction);
1391         pw.println("  isBouncerShowing(): " + isBouncerShowing());
1392         pw.println("  bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing());
1393         pw.println("  mAlternateBouncerReceivedDownTouch: " + mAlternateBouncerReceivedDownTouch);
1394         pw.println("  Registered KeyguardViewManagerCallbacks:");
1395         for (KeyguardViewManagerCallback callback : mCallbacks) {
1396             pw.println("      " + callback);
1397         }
1398 
1399         if (mOccludingAppBiometricUI != null) {
1400             pw.println("mOccludingAppBiometricUI:");
1401             mOccludingAppBiometricUI.dump(pw);
1402         }
1403     }
1404 
1405     @Override
onDozingChanged(boolean isDozing)1406     public void onDozingChanged(boolean isDozing) {
1407         setDozing(isDozing);
1408     }
1409 
1410     @Override
onFoldToAodAnimationChanged()1411     public void onFoldToAodAnimationChanged() {
1412         if (mFoldAodAnimationController != null) {
1413             mScreenOffAnimationPlaying = mFoldAodAnimationController.shouldPlayAnimation();
1414         }
1415     }
1416 
1417     /**
1418      * Add a callback to listen for changes
1419      */
addCallback(KeyguardViewManagerCallback callback)1420     public void addCallback(KeyguardViewManagerCallback callback) {
1421         mCallbacks.add(callback);
1422     }
1423 
1424     /**
1425      * Removes callback to stop receiving updates
1426      */
removeCallback(KeyguardViewManagerCallback callback)1427     public void removeCallback(KeyguardViewManagerCallback callback) {
1428         mCallbacks.remove(callback);
1429     }
1430 
1431     /**
1432      * Whether qs is currently expanded.
1433      */
getQsExpansion()1434     public float getQsExpansion() {
1435         return mQsExpansion;
1436     }
1437 
1438     /**
1439      * Update qs expansion.
1440      */
setQsExpansion(float qsExpansion)1441     public void setQsExpansion(float qsExpansion) {
1442         mQsExpansion = qsExpansion;
1443         for (KeyguardViewManagerCallback callback : mCallbacks) {
1444             callback.onQSExpansionChanged(mQsExpansion);
1445         }
1446     }
1447 
1448     /**
1449      * For any touches on the NPVC, show the primary bouncer if the alternate bouncer is currently
1450      * showing.
1451      */
onTouch(MotionEvent event)1452     public boolean onTouch(MotionEvent event) {
1453         boolean handledTouch = false;
1454         if (mAlternateBouncerInteractor.isVisibleState()) {
1455             final boolean downThenUp = event.getActionMasked() == MotionEvent.ACTION_UP
1456                     && mAlternateBouncerReceivedDownTouch;
1457             final boolean outsideTouch = event.getActionMasked() == MotionEvent.ACTION_OUTSIDE;
1458             if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1459                 mAlternateBouncerReceivedDownTouch = true;
1460             } else if ((downThenUp || outsideTouch)
1461                     && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) {
1462                 showPrimaryBouncer(true);
1463             }
1464             handledTouch = true;
1465         } else {
1466             mAlternateBouncerReceivedDownTouch = false;
1467         }
1468 
1469         // Forward NPVC touches to callbacks in case they want to respond to touches
1470         for (KeyguardViewManagerCallback callback: mCallbacks) {
1471             callback.onTouch(event);
1472         }
1473 
1474         return handledTouch;
1475     }
1476 
1477     /** Update keyguard position based on a tapped X coordinate. */
updateKeyguardPosition(float x)1478     public void updateKeyguardPosition(float x) {
1479         mPrimaryBouncerInteractor.setKeyguardPosition(x);
1480     }
1481 
1482     private static class DismissWithActionRequest {
1483         final OnDismissAction dismissAction;
1484         final Runnable cancelAction;
1485         final boolean afterKeyguardGone;
1486         final String message;
1487 
DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction, boolean afterKeyguardGone, String message)1488         DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction,
1489                 boolean afterKeyguardGone, String message) {
1490             this.dismissAction = dismissAction;
1491             this.cancelAction = cancelAction;
1492             this.afterKeyguardGone = afterKeyguardGone;
1493             this.message = message;
1494         }
1495     }
1496 
1497     /**
1498      * Request to authenticate using face.
1499      */
requestFace(boolean request)1500     public void requestFace(boolean request) {
1501         mKeyguardUpdateManager.requestFaceAuthOnOccludingApp(request);
1502     }
1503 
1504     /**
1505      * Request to authenticate using the fingerprint sensor.  If the fingerprint sensor is udfps,
1506      * uses the color provided by udfpsColor for the fingerprint icon.
1507      */
requestFp(boolean request, int udfpsColor)1508     public void requestFp(boolean request, int udfpsColor) {
1509         mKeyguardUpdateManager.requestFingerprintAuthOnOccludingApp(request);
1510         if (mOccludingAppBiometricUI != null) {
1511             mOccludingAppBiometricUI.requestUdfps(request, udfpsColor);
1512         }
1513     }
1514 
1515     /**
1516      * Returns if bouncer expansion is between 0 and 1 non-inclusive.
1517      */
isPrimaryBouncerInTransit()1518     public boolean isPrimaryBouncerInTransit() {
1519         return mPrimaryBouncerInteractor.isInTransit();
1520     }
1521 
1522     /**
1523      * Returns if bouncer is showing
1524      */
primaryBouncerIsShowing()1525     public boolean primaryBouncerIsShowing() {
1526         return mPrimaryBouncerInteractor.isFullyShowing();
1527     }
1528 
1529     /**
1530      * Returns if bouncer is scrimmed
1531      */
primaryBouncerIsScrimmed()1532     public boolean primaryBouncerIsScrimmed() {
1533         return mPrimaryBouncerInteractor.isScrimmed();
1534     }
1535 
1536     /**
1537      * Returns if bouncer is animating away
1538      */
bouncerIsAnimatingAway()1539     public boolean bouncerIsAnimatingAway() {
1540         return mPrimaryBouncerInteractor.isAnimatingAway();
1541     }
1542 
1543     /**
1544      * Returns if bouncer will dismiss with action
1545      */
primaryBouncerWillDismissWithAction()1546     public boolean primaryBouncerWillDismissWithAction() {
1547         return mPrimaryBouncerInteractor.willDismissWithAction();
1548     }
1549 
1550     /**
1551      * Returns if bouncer needs fullscreen bouncer. i.e. sim pin security method
1552      */
needsFullscreenBouncer()1553     public boolean needsFullscreenBouncer() {
1554         KeyguardSecurityModel.SecurityMode mode = mKeyguardSecurityModel.getSecurityMode(
1555                 KeyguardUpdateMonitor.getCurrentUser());
1556         return mode == KeyguardSecurityModel.SecurityMode.SimPin
1557                 || mode == KeyguardSecurityModel.SecurityMode.SimPuk;
1558     }
1559 
1560     /**
1561      * @Deprecated Delegate used to send show and hide events to an alternate bouncer.
1562      */
1563     public interface LegacyAlternateBouncer {
1564         /**
1565          * Show alternate authentication bouncer.
1566          * @return whether alternate auth method was newly shown
1567          */
showAlternateBouncer()1568         boolean showAlternateBouncer();
1569 
1570         /**
1571          * Hide alternate authentication bouncer
1572          * @return whether the alternate auth method was newly hidden
1573          */
hideAlternateBouncer()1574         boolean hideAlternateBouncer();
1575 
1576         /**
1577          * @return true if the alternate auth bouncer is showing
1578          */
isShowingAlternateBouncer()1579         boolean isShowingAlternateBouncer();
1580     }
1581 
1582     /**
1583      * Delegate used to send show and hide events to an alternate authentication method instead of
1584      * the regular pin/pattern/password bouncer.
1585      */
1586     public interface OccludingAppBiometricUI {
1587         /**
1588          * Use when an app occluding the keyguard would like to give the user ability to
1589          * unlock the device using udfps.
1590          *
1591          * @param color of the udfps icon. should have proper contrast with its background. only
1592          *              used if requestUdfps = true
1593          */
requestUdfps(boolean requestUdfps, int color)1594         void requestUdfps(boolean requestUdfps, int color);
1595 
1596         /**
1597          * print information for the alternate bouncer registered
1598          */
dump(PrintWriter pw)1599         void dump(PrintWriter pw);
1600     }
1601 
1602     /**
1603      * Callback for KeyguardViewManager state changes.
1604      */
1605     public interface KeyguardViewManagerCallback {
1606         /**
1607          * Set the amount qs is expanded. For example, swipe down from the top of the
1608          * lock screen to start the full QS expansion.
1609          */
onQSExpansionChanged(float qsExpansion)1610         default void onQSExpansionChanged(float qsExpansion) { }
1611 
1612         /**
1613          * Forward touch events to callbacks
1614          */
onTouch(MotionEvent event)1615         default void onTouch(MotionEvent event) { }
1616     }
1617 }
1618