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