1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.systemui.statusbar.phone;
18 
19 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
20 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
21 
22 import android.content.Context;
23 import android.content.res.ColorStateList;
24 import android.hardware.biometrics.BiometricSourceType;
25 import android.os.Handler;
26 import android.os.UserHandle;
27 import android.os.UserManager;
28 import android.util.Log;
29 import android.view.KeyEvent;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.view.WindowInsets;
33 
34 import com.android.internal.policy.SystemBarUtils;
35 import com.android.keyguard.KeyguardHostViewController;
36 import com.android.keyguard.KeyguardRootViewController;
37 import com.android.keyguard.KeyguardSecurityModel;
38 import com.android.keyguard.KeyguardSecurityView;
39 import com.android.keyguard.KeyguardUpdateMonitor;
40 import com.android.keyguard.KeyguardUpdateMonitorCallback;
41 import com.android.keyguard.ViewMediatorCallback;
42 import com.android.keyguard.dagger.KeyguardBouncerComponent;
43 import com.android.systemui.DejankUtils;
44 import com.android.systemui.classifier.FalsingCollector;
45 import com.android.systemui.dagger.qualifiers.RootView;
46 import com.android.systemui.keyguard.DismissCallbackRegistry;
47 import com.android.systemui.shared.system.SysUiStatsLog;
48 import com.android.systemui.statusbar.policy.KeyguardStateController;
49 import com.android.systemui.util.ListenerSet;
50 
51 import java.io.PrintWriter;
52 import java.util.ArrayList;
53 import java.util.List;
54 
55 import javax.inject.Inject;
56 
57 /**
58  * A class which manages the bouncer on the lockscreen.
59  */
60 public class KeyguardBouncer {
61 
62     private static final String TAG = "KeyguardBouncer";
63     static final long BOUNCER_FACE_DELAY = 1200;
64     public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
65     public static final float EXPANSION_HIDDEN = 1f;
66     public static final float EXPANSION_VISIBLE = 0f;
67 
68     protected final Context mContext;
69     protected final ViewMediatorCallback mCallback;
70     protected final ViewGroup mContainer;
71     private final FalsingCollector mFalsingCollector;
72     private final DismissCallbackRegistry mDismissCallbackRegistry;
73     private final Handler mHandler;
74     private final List<BouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>();
75     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
76     private final KeyguardStateController mKeyguardStateController;
77     private final KeyguardSecurityModel mKeyguardSecurityModel;
78     private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
79     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
80             new KeyguardUpdateMonitorCallback() {
81                 @Override
82                 public void onStrongAuthStateChanged(int userId) {
83                     mBouncerPromptReason = mCallback.getBouncerPromptReason();
84                 }
85 
86                 @Override
87                 public void onLockedOutStateChanged(BiometricSourceType type) {
88                     if (type == BiometricSourceType.FINGERPRINT) {
89                         mBouncerPromptReason = mCallback.getBouncerPromptReason();
90                     }
91                 }
92             };
93     private final Runnable mRemoveViewRunnable = this::removeView;
94     private final KeyguardBypassController mKeyguardBypassController;
95     private KeyguardHostViewController mKeyguardViewController;
96     private final ListenerSet<KeyguardResetCallback> mResetCallbacks = new ListenerSet<>();
97     private final Runnable mResetRunnable = ()-> {
98         if (mKeyguardViewController != null) {
99             mKeyguardViewController.resetSecurityContainer();
100             for (KeyguardResetCallback callback : mResetCallbacks) {
101                 callback.onKeyguardReset();
102             }
103         }
104     };
105 
106     private int mStatusBarHeight;
107     private float mExpansion = EXPANSION_HIDDEN;
108     protected ViewGroup mRoot;
109     private KeyguardRootViewController mRootViewController;
110     private boolean mShowingSoon;
111     private int mBouncerPromptReason;
112     private boolean mIsAnimatingAway;
113     private boolean mIsScrimmed;
114 
KeyguardBouncer(Context context, ViewMediatorCallback callback, ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector, BouncerExpansionCallback expansionCallback, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardBypassController keyguardBypassController, Handler handler, KeyguardSecurityModel keyguardSecurityModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory)115     private KeyguardBouncer(Context context, ViewMediatorCallback callback,
116             ViewGroup container,
117             DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
118             BouncerExpansionCallback expansionCallback,
119             KeyguardStateController keyguardStateController,
120             KeyguardUpdateMonitor keyguardUpdateMonitor,
121             KeyguardBypassController keyguardBypassController, Handler handler,
122             KeyguardSecurityModel keyguardSecurityModel,
123             KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
124         mContext = context;
125         mCallback = callback;
126         mContainer = container;
127         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
128         mFalsingCollector = falsingCollector;
129         mDismissCallbackRegistry = dismissCallbackRegistry;
130         mHandler = handler;
131         mKeyguardStateController = keyguardStateController;
132         mKeyguardSecurityModel = keyguardSecurityModel;
133         mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
134         mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
135         mKeyguardBypassController = keyguardBypassController;
136         mExpansionCallbacks.add(expansionCallback);
137     }
138 
139     /**
140      * Enable/disable only the back button
141      */
setBackButtonEnabled(boolean enabled)142     public void setBackButtonEnabled(boolean enabled) {
143         int vis = mContainer.getSystemUiVisibility();
144         if (enabled) {
145             vis &= ~View.STATUS_BAR_DISABLE_BACK;
146         } else {
147             vis |= View.STATUS_BAR_DISABLE_BACK;
148         }
149         mContainer.setSystemUiVisibility(vis);
150     }
151 
show(boolean resetSecuritySelection)152     public void show(boolean resetSecuritySelection) {
153         show(resetSecuritySelection, true /* scrimmed */);
154     }
155 
156     /**
157      * Shows the bouncer.
158      *
159      * @param resetSecuritySelection Cleans keyguard view
160      * @param isScrimmed true when the bouncer show show scrimmed, false when the user will be
161      *                 dragging it and translation should be deferred.
162      */
show(boolean resetSecuritySelection, boolean isScrimmed)163     public void show(boolean resetSecuritySelection, boolean isScrimmed) {
164         final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
165         if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
166             // In split system user mode, we never unlock system user.
167             return;
168         }
169         ensureView();
170         mIsScrimmed = isScrimmed;
171 
172         // On the keyguard, we want to show the bouncer when the user drags up, but it's
173         // not correct to end the falsing session. We still need to verify if those touches
174         // are valid.
175         // Later, at the end of the animation, when the bouncer is at the top of the screen,
176         // onFullyShown() will be called and FalsingManager will stop recording touches.
177         if (isScrimmed) {
178             setExpansion(EXPANSION_VISIBLE);
179         }
180 
181         if (resetSecuritySelection) {
182             // showPrimarySecurityScreen() updates the current security method. This is needed in
183             // case we are already showing and the current security method changed.
184             showPrimarySecurityScreen();
185         }
186 
187         if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
188             return;
189         }
190 
191         final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
192         final boolean isSystemUser =
193                 UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
194         final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
195 
196         // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
197         // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
198         if (allowDismissKeyguard && mKeyguardViewController.dismiss(activeUserId)) {
199             return;
200         }
201 
202         // This condition may indicate an error on Android, so log it.
203         if (!allowDismissKeyguard) {
204             Log.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
205         }
206 
207         mShowingSoon = true;
208 
209         // Split up the work over multiple frames.
210         DejankUtils.removeCallbacks(mResetRunnable);
211         if (mKeyguardStateController.isFaceAuthEnabled() && !needsFullscreenBouncer()
212                 && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
213                 && !mKeyguardBypassController.getBypassEnabled()) {
214             mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
215         } else {
216             DejankUtils.postAfterTraversal(mShowRunnable);
217         }
218 
219         mCallback.onBouncerVisiblityChanged(true /* shown */);
220         dispatchStartingToShow();
221     }
222 
isScrimmed()223     public boolean isScrimmed() {
224         return mIsScrimmed;
225     }
226 
227     /**
228      * This method must be called at the end of the bouncer animation when
229      * the translation is performed manually by the user, otherwise FalsingManager
230      * will never be notified and its internal state will be out of sync.
231      */
onFullyShown()232     private void onFullyShown() {
233         mFalsingCollector.onBouncerShown();
234         if (mKeyguardViewController == null) {
235             Log.wtf(TAG, "onFullyShown when view was null");
236         } else {
237             mKeyguardViewController.onResume();
238             if (mRoot != null) {
239                 mRoot.announceForAccessibility(
240                         mKeyguardViewController.getAccessibilityTitleForCurrentMode());
241             }
242         }
243     }
244 
245     /**
246      * @see #onFullyShown()
247      */
onFullyHidden()248     private void onFullyHidden() {
249         cancelShowRunnable();
250         setVisibility(View.INVISIBLE);
251         mFalsingCollector.onBouncerHidden();
252         DejankUtils.postAfterTraversal(mResetRunnable);
253     }
254 
setVisibility(@iew.Visibility int visibility)255     private void setVisibility(@View.Visibility int visibility) {
256         if (mRoot != null) {
257             mRoot.setVisibility(visibility);
258             dispatchVisibilityChanged();
259         }
260     }
261 
262     private final Runnable mShowRunnable = new Runnable() {
263         @Override
264         public void run() {
265             setVisibility(View.VISIBLE);
266             showPromptReason(mBouncerPromptReason);
267             final CharSequence customMessage = mCallback.consumeCustomMessage();
268             if (customMessage != null) {
269                 mKeyguardViewController.showErrorMessage(customMessage);
270             }
271             mKeyguardViewController.appear(mStatusBarHeight);
272             mShowingSoon = false;
273             if (mExpansion == EXPANSION_VISIBLE) {
274                 mKeyguardViewController.onResume();
275                 mKeyguardViewController.resetSecurityContainer();
276                 showPromptReason(mBouncerPromptReason);
277             }
278         }
279     };
280 
281     /**
282      * Show a string explaining why the security view needs to be solved.
283      *
284      * @param reason a flag indicating which string should be shown, see
285      *               {@link KeyguardSecurityView#PROMPT_REASON_NONE}
286      *               and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
287      */
showPromptReason(int reason)288     public void showPromptReason(int reason) {
289         if (mKeyguardViewController != null) {
290             mKeyguardViewController.showPromptReason(reason);
291         } else {
292             Log.w(TAG, "Trying to show prompt reason on empty bouncer");
293         }
294     }
295 
showMessage(String message, ColorStateList colorState)296     public void showMessage(String message, ColorStateList colorState) {
297         if (mKeyguardViewController != null) {
298             mKeyguardViewController.showMessage(message, colorState);
299         } else {
300             Log.w(TAG, "Trying to show message on empty bouncer");
301         }
302     }
303 
cancelShowRunnable()304     private void cancelShowRunnable() {
305         DejankUtils.removeCallbacks(mShowRunnable);
306         mHandler.removeCallbacks(mShowRunnable);
307         mShowingSoon = false;
308     }
309 
showWithDismissAction(OnDismissAction r, Runnable cancelAction)310     public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
311         ensureView();
312         setDismissAction(r, cancelAction);
313         show(false /* resetSecuritySelection */);
314     }
315 
316     /**
317      * Set the actions to run when the keyguard is dismissed or when the dismiss is cancelled. Those
318      * actions will still be run even if this bouncer is not shown, for instance when authenticating
319      * with an alternate authenticator like the UDFPS.
320      */
setDismissAction(OnDismissAction r, Runnable cancelAction)321     public void setDismissAction(OnDismissAction r, Runnable cancelAction) {
322         mKeyguardViewController.setOnDismissAction(r, cancelAction);
323     }
324 
hide(boolean destroyView)325     public void hide(boolean destroyView) {
326         if (isShowing()) {
327             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
328                     SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
329             mDismissCallbackRegistry.notifyDismissCancelled();
330         }
331         mIsScrimmed = false;
332         mFalsingCollector.onBouncerHidden();
333         mCallback.onBouncerVisiblityChanged(false /* shown */);
334         cancelShowRunnable();
335         if (mKeyguardViewController != null) {
336             mKeyguardViewController.cancelDismissAction();
337             mKeyguardViewController.cleanUp();
338         }
339         mIsAnimatingAway = false;
340         if (mRoot != null) {
341             setVisibility(View.INVISIBLE);
342             if (destroyView) {
343 
344                 // We have a ViewFlipper that unregisters a broadcast when being detached, which may
345                 // be slow because of AM lock contention during unlocking. We can delay it a bit.
346                 mHandler.postDelayed(mRemoveViewRunnable, 50);
347             }
348         }
349     }
350 
351     /**
352      * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
353      */
startPreHideAnimation(Runnable runnable)354     public void startPreHideAnimation(Runnable runnable) {
355         mIsAnimatingAway = true;
356         if (mKeyguardViewController != null) {
357             mKeyguardViewController.startDisappearAnimation(runnable);
358         } else if (runnable != null) {
359             runnable.run();
360         }
361     }
362 
363     /**
364      * Reset the state of the view.
365      */
reset()366     public void reset() {
367         cancelShowRunnable();
368         inflateView();
369         mFalsingCollector.onBouncerHidden();
370     }
371 
onScreenTurnedOff()372     public void onScreenTurnedOff() {
373         if (mKeyguardViewController != null
374                 && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
375             mKeyguardViewController.onPause();
376         }
377     }
378 
isShowing()379     public boolean isShowing() {
380         return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
381                 && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
382     }
383 
384     /**
385      * {@link #show(boolean)} was called but we're not showing yet, or being dragged.
386      */
inTransit()387     public boolean inTransit() {
388         return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
389     }
390 
getShowingSoon()391     public boolean getShowingSoon() {
392         return mShowingSoon;
393     }
394 
395     /**
396      * @return {@code true} when bouncer's pre-hide animation already started but isn't completely
397      *         hidden yet, {@code false} otherwise.
398      */
isAnimatingAway()399     public boolean isAnimatingAway() {
400         return mIsAnimatingAway;
401     }
402 
prepare()403     public void prepare() {
404         boolean wasInitialized = mRoot != null;
405         ensureView();
406         if (wasInitialized) {
407             showPrimarySecurityScreen();
408         }
409         mBouncerPromptReason = mCallback.getBouncerPromptReason();
410     }
411 
showPrimarySecurityScreen()412     private void showPrimarySecurityScreen() {
413         mKeyguardViewController.showPrimarySecurityScreen();
414     }
415 
416     /**
417      * Current notification panel expansion
418      * @param fraction 0 when notification panel is collapsed and 1 when expanded.
419      * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
420      */
setExpansion(float fraction)421     public void setExpansion(float fraction) {
422         float oldExpansion = mExpansion;
423         boolean expansionChanged = mExpansion != fraction;
424         mExpansion = fraction;
425         if (mKeyguardViewController != null && !mIsAnimatingAway) {
426             mKeyguardViewController.setExpansion(fraction);
427         }
428 
429         if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
430             onFullyShown();
431             dispatchFullyShown();
432         } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
433             onFullyHidden();
434             dispatchFullyHidden();
435         } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
436             dispatchStartingToHide();
437             if (mKeyguardViewController != null) {
438                 mKeyguardViewController.onStartingToHide();
439             }
440         }
441 
442         if (expansionChanged) {
443             dispatchExpansionChanged();
444         }
445     }
446 
willDismissWithAction()447     public boolean willDismissWithAction() {
448         return mKeyguardViewController != null && mKeyguardViewController.hasDismissActions();
449     }
450 
getTop()451     public int getTop() {
452         if (mKeyguardViewController == null) {
453             return 0;
454         }
455 
456         return mKeyguardViewController.getTop();
457     }
458 
ensureView()459     protected void ensureView() {
460         // Removal of the view might be deferred to reduce unlock latency,
461         // in this case we need to force the removal, otherwise we'll
462         // end up in an unpredictable state.
463         boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
464         if (mRoot == null || forceRemoval) {
465             inflateView();
466         }
467     }
468 
inflateView()469     protected void inflateView() {
470         removeView();
471         mHandler.removeCallbacks(mRemoveViewRunnable);
472         KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create();
473         mRootViewController = component.getKeyguardRootViewController();
474         mRootViewController.init();
475         mRoot = mRootViewController.getView();  // TODO(b/166448040): Don't access root view here.
476         mKeyguardViewController = component.getKeyguardHostViewController();
477         mKeyguardViewController.init();
478 
479         mContainer.addView(mRoot, mContainer.getChildCount());
480         mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
481         setVisibility(View.INVISIBLE);
482 
483         final WindowInsets rootInsets = mRoot.getRootWindowInsets();
484         if (rootInsets != null) {
485             mRoot.dispatchApplyWindowInsets(rootInsets);
486         }
487     }
488 
removeView()489     protected void removeView() {
490         if (mRoot != null && mRoot.getParent() == mContainer) {
491             mContainer.removeView(mRoot);
492             mRoot = null;
493         }
494     }
495 
496     /**
497      * @return True if and only if the security method should be shown before showing the
498      * notifications on Keyguard, like SIM PIN/PUK.
499      */
needsFullscreenBouncer()500     public boolean needsFullscreenBouncer() {
501         SecurityMode mode = mKeyguardSecurityModel.getSecurityMode(
502                 KeyguardUpdateMonitor.getCurrentUser());
503         return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
504     }
505 
506     /**
507      * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which
508      * makes this method much faster.
509      */
isFullscreenBouncer()510     public boolean isFullscreenBouncer() {
511         if (mKeyguardViewController != null) {
512             SecurityMode mode = mKeyguardViewController.getCurrentSecurityMode();
513             return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
514         }
515         return false;
516     }
517 
518     /**
519      * WARNING: This method might cause Binder calls.
520      */
isSecure()521     public boolean isSecure() {
522         return mKeyguardSecurityModel.getSecurityMode(
523                 KeyguardUpdateMonitor.getCurrentUser()) != SecurityMode.None;
524     }
525 
shouldDismissOnMenuPressed()526     public boolean shouldDismissOnMenuPressed() {
527         return mKeyguardViewController.shouldEnableMenuKey();
528     }
529 
interceptMediaKey(KeyEvent event)530     public boolean interceptMediaKey(KeyEvent event) {
531         ensureView();
532         return mKeyguardViewController.interceptMediaKey(event);
533     }
534 
535     /**
536      * @return true if the pre IME back event should be handled
537      */
dispatchBackKeyEventPreIme()538     public boolean dispatchBackKeyEventPreIme() {
539         ensureView();
540         return mKeyguardViewController.dispatchBackKeyEventPreIme();
541     }
542 
notifyKeyguardAuthenticated(boolean strongAuth)543     public void notifyKeyguardAuthenticated(boolean strongAuth) {
544         ensureView();
545         mKeyguardViewController.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
546     }
547 
dispatchFullyShown()548     private void dispatchFullyShown() {
549         for (BouncerExpansionCallback callback : mExpansionCallbacks) {
550             callback.onFullyShown();
551         }
552     }
553 
dispatchStartingToHide()554     private void dispatchStartingToHide() {
555         for (BouncerExpansionCallback callback : mExpansionCallbacks) {
556             callback.onStartingToHide();
557         }
558     }
559 
dispatchStartingToShow()560     private void dispatchStartingToShow() {
561         for (BouncerExpansionCallback callback : mExpansionCallbacks) {
562             callback.onStartingToShow();
563         }
564     }
565 
dispatchFullyHidden()566     private void dispatchFullyHidden() {
567         for (BouncerExpansionCallback callback : mExpansionCallbacks) {
568             callback.onFullyHidden();
569         }
570     }
571 
dispatchExpansionChanged()572     private void dispatchExpansionChanged() {
573         for (BouncerExpansionCallback callback : mExpansionCallbacks) {
574             callback.onExpansionChanged(mExpansion);
575         }
576     }
577 
dispatchVisibilityChanged()578     private void dispatchVisibilityChanged() {
579         for (BouncerExpansionCallback callback : mExpansionCallbacks) {
580             callback.onVisibilityChanged(mRoot.getVisibility() == View.VISIBLE);
581         }
582     }
583 
584     /**
585      * Apply keyguard configuration from the currently active resources. This can be called when the
586      * device configuration changes, to re-apply some resources that are qualified on the device
587      * configuration.
588      */
updateResources()589     public void updateResources() {
590         if (mKeyguardViewController != null) {
591             mKeyguardViewController.updateResources();
592         }
593     }
594 
dump(PrintWriter pw)595     public void dump(PrintWriter pw) {
596         pw.println("KeyguardBouncer");
597         pw.println("  isShowing(): " + isShowing());
598         pw.println("  mStatusBarHeight: " + mStatusBarHeight);
599         pw.println("  mExpansion: " + mExpansion);
600         pw.println("  mKeyguardViewController; " + mKeyguardViewController);
601         pw.println("  mShowingSoon: " + mShowingSoon);
602         pw.println("  mBouncerPromptReason: " + mBouncerPromptReason);
603         pw.println("  mIsAnimatingAway: " + mIsAnimatingAway);
604     }
605 
606     /** Update keyguard position based on a tapped X coordinate. */
updateKeyguardPosition(float x)607     public void updateKeyguardPosition(float x) {
608         if (mKeyguardViewController != null) {
609             mKeyguardViewController.updateKeyguardPosition(x);
610         }
611     }
612 
addKeyguardResetCallback(KeyguardResetCallback callback)613     public void addKeyguardResetCallback(KeyguardResetCallback callback) {
614         mResetCallbacks.addIfAbsent(callback);
615     }
616 
removeKeyguardResetCallback(KeyguardResetCallback callback)617     public void removeKeyguardResetCallback(KeyguardResetCallback callback) {
618         mResetCallbacks.remove(callback);
619     }
620 
621     public interface BouncerExpansionCallback {
onFullyShown()622         void onFullyShown();
onStartingToHide()623         void onStartingToHide();
onStartingToShow()624         void onStartingToShow();
onFullyHidden()625         void onFullyHidden();
626 
627         /**
628          * From 0f {@link KeyguardBouncer#EXPANSION_VISIBLE} when fully visible
629          * to 1f {@link KeyguardBouncer#EXPANSION_HIDDEN} when fully hidden
630          */
onExpansionChanged(float bouncerHideAmount)631         default void onExpansionChanged(float bouncerHideAmount) {}
632 
633         /**
634          * Invoked when visibility of KeyguardBouncer has changed.
635          * Note the bouncer expansion can be {@link KeyguardBouncer#EXPANSION_VISIBLE}, but the
636          * view's visibility can be {@link View.INVISIBLE}.
637          */
onVisibilityChanged(boolean isVisible)638         default void onVisibilityChanged(boolean isVisible) {}
639     }
640 
641     public interface KeyguardResetCallback {
onKeyguardReset()642         void onKeyguardReset();
643     }
644 
645     /** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
646     public static class Factory {
647         private final Context mContext;
648         private final ViewMediatorCallback mCallback;
649         private final DismissCallbackRegistry mDismissCallbackRegistry;
650         private final FalsingCollector mFalsingCollector;
651         private final KeyguardStateController mKeyguardStateController;
652         private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
653         private final KeyguardBypassController mKeyguardBypassController;
654         private final Handler mHandler;
655         private final KeyguardSecurityModel mKeyguardSecurityModel;
656         private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
657 
658         @Inject
Factory(Context context, ViewMediatorCallback callback, DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardBypassController keyguardBypassController, Handler handler, KeyguardSecurityModel keyguardSecurityModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory)659         public Factory(Context context, ViewMediatorCallback callback,
660                 DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
661                 KeyguardStateController keyguardStateController,
662                 KeyguardUpdateMonitor keyguardUpdateMonitor,
663                 KeyguardBypassController keyguardBypassController, Handler handler,
664                 KeyguardSecurityModel keyguardSecurityModel,
665                 KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
666             mContext = context;
667             mCallback = callback;
668             mDismissCallbackRegistry = dismissCallbackRegistry;
669             mFalsingCollector = falsingCollector;
670             mKeyguardStateController = keyguardStateController;
671             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
672             mKeyguardBypassController = keyguardBypassController;
673             mHandler = handler;
674             mKeyguardSecurityModel = keyguardSecurityModel;
675             mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
676         }
677 
create(@ootView ViewGroup container, BouncerExpansionCallback expansionCallback)678         public KeyguardBouncer create(@RootView ViewGroup container,
679                 BouncerExpansionCallback expansionCallback) {
680             return new KeyguardBouncer(mContext, mCallback, container,
681                     mDismissCallbackRegistry, mFalsingCollector, expansionCallback,
682                     mKeyguardStateController, mKeyguardUpdateMonitor,
683                     mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
684                     mKeyguardBouncerComponentFactory);
685         }
686     }
687 }
688