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