• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.car.keyguard;
18 
19 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
20 
21 import android.animation.Animator;
22 import android.animation.AnimatorListenerAdapter;
23 import android.content.Context;
24 import android.content.res.Resources;
25 import android.graphics.PixelFormat;
26 import android.os.Bundle;
27 import android.os.UserHandle;
28 import android.util.Log;
29 import android.view.Gravity;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.view.ViewRootImpl;
33 import android.view.WindowManager;
34 
35 import androidx.annotation.MainThread;
36 
37 import com.android.car.ui.FocusParkingView;
38 import com.android.internal.widget.LockPatternUtils;
39 import com.android.internal.widget.LockPatternView;
40 import com.android.keyguard.KeyguardMessageAreaController;
41 import com.android.keyguard.KeyguardSecurityModel;
42 import com.android.keyguard.KeyguardUpdateMonitor;
43 import com.android.keyguard.KeyguardViewController;
44 import com.android.keyguard.ViewMediatorCallback;
45 import com.android.keyguard.dagger.KeyguardBouncerComponent;
46 import com.android.systemui.R;
47 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
48 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
49 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
50 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
51 import com.android.systemui.bouncer.ui.BouncerView;
52 import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
53 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;
54 import com.android.systemui.car.systembar.CarSystemBarController;
55 import com.android.systemui.car.window.OverlayViewController;
56 import com.android.systemui.car.window.OverlayViewGlobalStateController;
57 import com.android.systemui.car.window.SystemUIOverlayWindowController;
58 import com.android.systemui.dagger.SysUISingleton;
59 import com.android.systemui.dagger.qualifiers.Main;
60 import com.android.systemui.flags.FeatureFlags;
61 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
62 import com.android.systemui.log.BouncerLogger;
63 import com.android.systemui.settings.UserTracker;
64 import com.android.systemui.shade.ShadeExpansionStateManager;
65 import com.android.systemui.shade.ShadeViewController;
66 import com.android.systemui.statusbar.phone.BiometricUnlockController;
67 import com.android.systemui.statusbar.phone.CentralSurfaces;
68 import com.android.systemui.statusbar.phone.KeyguardBypassController;
69 import com.android.systemui.statusbar.policy.KeyguardStateController;
70 import com.android.systemui.toast.SystemUIToast;
71 import com.android.systemui.toast.ToastFactory;
72 import com.android.systemui.util.concurrency.DelayableExecutor;
73 
74 import dagger.Lazy;
75 
76 import javax.inject.Inject;
77 
78 /**
79  * Automotive implementation of the {@link KeyguardViewController}. It controls the Keyguard View
80  * that is mounted to the SystemUIOverlayWindow.
81  */
82 @SysUISingleton
83 public class CarKeyguardViewController extends OverlayViewController implements
84         KeyguardViewController {
85     private static final String TAG = "CarKeyguardViewController";
86     private static final boolean DEBUG = true;
87     private static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f;
88     private static final float TOAST_PARAMS_VERTICAL_WEIGHT = 1.0f;
89 
90     private final Context mContext;
91     private final UserTracker mUserTracker;
92     private final DelayableExecutor mMainExecutor;
93     private final WindowManager mWindowManager;
94     private final ToastFactory mToastFactory;
95     private final FocusParkingView mFocusParkingView;
96     private final KeyguardStateController mKeyguardStateController;
97     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
98     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
99     private final ViewMediatorCallback mViewMediatorCallback;
100     private final CarSystemBarController mCarSystemBarController;
101     private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
102     private final KeyguardSecurityModel mKeyguardSecurityModel;
103     private final KeyguardBouncerViewModel mKeyguardBouncerViewModel;
104     private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
105     private final LockPatternUtils mLockPatternUtils;
106     private final BouncerView mBouncerView;
107     private final PrimaryBouncerExpansionCallback mExpansionCallback =
108             new PrimaryBouncerExpansionCallback() {
109                 @Override
110                 public void onFullyShown() {
111                     LockPatternView patternView = getLayout().findViewById(R.id.lockPatternView);
112                     if (patternView != null) {
113                         patternView.setOnFocusChangeListener((v, hasFocus) -> {
114                             if (hasFocus) {
115                                 makeOverlayToast(R.string.lockpattern_does_not_support_rotary);
116                             }
117                         });
118                     }
119                 }
120 
121                 @Override
122                 public void onStartingToHide() {
123                 }
124 
125                 @Override
126                 public void onStartingToShow() {
127                     // TODO: Remove this code block when b/158386500 is addressed properly.
128                     int currentUser = mUserTracker.getUserId();
129                     if (mLockPatternUtils.getCredentialTypeForUser(currentUser)
130                             == CREDENTIAL_TYPE_PATTERN
131                             && !mLockPatternUtils.isVisiblePatternEnabled(currentUser)) {
132                         mLockPatternUtils.setVisiblePatternEnabled(true, currentUser);
133                         Log.w(TAG, "Pattern is invisible for the current user. "
134                                 + "Setting it to be visible.");
135                     }
136                 }
137 
138                 @Override
139                 public void onFullyHidden() {
140                 }
141 
142                 @Override
143                 public void onVisibilityChanged(boolean isVisible) {
144                 }
145 
146                 @Override
147                 public void onExpansionChanged(float bouncerHideAmount) {
148                 }
149             };
150     private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
151     private final BouncerLogger mBouncerLogger;
152     private final FeatureFlags mFeatureFlags;
153     private final BouncerMessageInteractor mBouncerMessageInteractor;
154 
155     private OnKeyguardCancelClickedListener mKeyguardCancelClickedListener;
156     private boolean mShowing;
157     private boolean mIsSleeping;
158     private int mToastShowDurationMillisecond;
159     private ViewGroup mKeyguardContainer;
160     private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
161 
162     @Inject
CarKeyguardViewController( Context context, UserTracker userTracker, @Main DelayableExecutor mainExecutor, WindowManager windowManager, ToastFactory toastFactory, SystemUIOverlayWindowController systemUIOverlayWindowController, OverlayViewGlobalStateController overlayViewGlobalStateController, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, Lazy<BiometricUnlockController> biometricUnlockControllerLazy, ViewMediatorCallback viewMediatorCallback, CarSystemBarController carSystemBarController, PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor, PrimaryBouncerInteractor primaryBouncerInteractor, KeyguardSecurityModel keyguardSecurityModel, KeyguardBouncerViewModel keyguardBouncerViewModel, PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory, LockPatternUtils lockPatternUtils, BouncerView bouncerView, KeyguardMessageAreaController.Factory messageAreaControllerFactory, BouncerLogger bouncerLogger, FeatureFlags featureFlags, BouncerMessageInteractor bouncerMessageInteractor)163     public CarKeyguardViewController(
164             Context context,
165             UserTracker userTracker,
166             @Main DelayableExecutor mainExecutor,
167             WindowManager windowManager,
168             ToastFactory toastFactory,
169             SystemUIOverlayWindowController systemUIOverlayWindowController,
170             OverlayViewGlobalStateController overlayViewGlobalStateController,
171             KeyguardStateController keyguardStateController,
172             KeyguardUpdateMonitor keyguardUpdateMonitor,
173             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
174             ViewMediatorCallback viewMediatorCallback,
175             CarSystemBarController carSystemBarController,
176             PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,
177             PrimaryBouncerInteractor primaryBouncerInteractor,
178             KeyguardSecurityModel keyguardSecurityModel,
179             KeyguardBouncerViewModel keyguardBouncerViewModel,
180             PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
181             KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
182             LockPatternUtils lockPatternUtils,
183             BouncerView bouncerView,
184             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
185             BouncerLogger bouncerLogger,
186             FeatureFlags featureFlags,
187             BouncerMessageInteractor bouncerMessageInteractor) {
188 
189         super(R.id.keyguard_stub, overlayViewGlobalStateController);
190 
191         mContext = context;
192         mUserTracker = userTracker;
193         mMainExecutor = mainExecutor;
194         mWindowManager = windowManager;
195         mToastFactory = toastFactory;
196         mFocusParkingView = systemUIOverlayWindowController.getBaseLayout().findViewById(
197                 R.id.focus_parking_view);
198         mKeyguardStateController = keyguardStateController;
199         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
200         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
201         mViewMediatorCallback = viewMediatorCallback;
202         mCarSystemBarController = carSystemBarController;
203         mPrimaryBouncerInteractor = primaryBouncerInteractor;
204         mKeyguardSecurityModel = keyguardSecurityModel;
205         mKeyguardBouncerViewModel = keyguardBouncerViewModel;
206         mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
207         mLockPatternUtils = lockPatternUtils;
208         mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
209         mBouncerView = bouncerView;
210 
211         mToastShowDurationMillisecond = mContext.getResources().getInteger(
212                 R.integer.car_keyguard_toast_show_duration_millisecond);
213         mMessageAreaControllerFactory = messageAreaControllerFactory;
214         mBouncerLogger = bouncerLogger;
215         mFeatureFlags = featureFlags;
216         mBouncerMessageInteractor = bouncerMessageInteractor;
217         primaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback);
218     }
219 
220     @Override
getFocusAreaViewId()221     protected int getFocusAreaViewId() {
222         return R.id.keyguard_container;
223     }
224 
225     @Override
shouldShowNavigationBarInsets()226     protected boolean shouldShowNavigationBarInsets() {
227         return true;
228     }
229 
230     @Override
onFinishInflate()231     public void onFinishInflate() {
232         mKeyguardContainer = getLayout().findViewById(R.id.keyguard_container);
233         KeyguardBouncerViewBinder.bind(mKeyguardContainer,
234                 mKeyguardBouncerViewModel, mPrimaryBouncerToGoneTransitionViewModel,
235                 mKeyguardBouncerComponentFactory,
236                 mMessageAreaControllerFactory,
237                 mBouncerMessageInteractor,
238                 mBouncerLogger,
239                 mFeatureFlags);
240         mBiometricUnlockControllerLazy.get().setKeyguardViewController(this);
241     }
242 
243     @Override
244     @MainThread
notifyKeyguardAuthenticated(boolean strongAuth)245     public void notifyKeyguardAuthenticated(boolean strongAuth) {
246         mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
247     }
248 
249     @Override
250     @MainThread
showPrimaryBouncer(boolean scrimmed)251     public void showPrimaryBouncer(boolean scrimmed) {
252         if (mShowing && !mPrimaryBouncerInteractor.isFullyShowing()) {
253             mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
254         }
255     }
256 
257     @Override
258     @MainThread
show(Bundle options)259     public void show(Bundle options) {
260         if (mShowing) return;
261 
262         mShowing = true;
263         mKeyguardStateController.notifyKeyguardState(mShowing,
264                 mKeyguardStateController.isOccluded());
265         mCarSystemBarController.showAllKeyguardButtons(/* isSetUp= */ true);
266         start();
267         reset(/* hideBouncerWhenShowing= */ false);
268         notifyKeyguardUpdateMonitor();
269     }
270 
271     @Override
272     @MainThread
hide(long startTime, long fadeoutDuration)273     public void hide(long startTime, long fadeoutDuration) {
274         if (!mShowing || mIsSleeping) return;
275 
276         mViewMediatorCallback.readyForKeyguardDone();
277         mShowing = false;
278         mKeyguardStateController.notifyKeyguardState(mShowing,
279                 mKeyguardStateController.isOccluded());
280         mPrimaryBouncerInteractor.hide();
281         mCarSystemBarController.showAllNavigationButtons(/* isSetUp= */ true);
282         stop();
283         mKeyguardStateController.notifyKeyguardDoneFading();
284         mMainExecutor.execute(mViewMediatorCallback::keyguardGone);
285         notifyKeyguardUpdateMonitor();
286     }
287 
288     @Override
reset(boolean hideBouncerWhenShowing)289     public void reset(boolean hideBouncerWhenShowing) {
290         if (mIsSleeping) return;
291 
292         mMainExecutor.execute(() -> {
293             if (mShowing) {
294                 if (!isSecure()) {
295                     dismissAndCollapse();
296                 } else {
297                     resetBouncer();
298                 }
299                 mKeyguardUpdateMonitor.sendKeyguardReset();
300                 notifyKeyguardUpdateMonitor();
301             } else {
302                 // This is necessary in order to address an inconsistency between the keyguard
303                 // service and the keyguard views.
304                 // TODO: Investigate the source of the inconsistency.
305                 show(/* options= */ null);
306             }
307         });
308     }
309 
310     @Override
hideAlternateBouncer(boolean forceUpdateScrim)311     public void hideAlternateBouncer(boolean forceUpdateScrim) {
312         // no-op
313     }
314 
315     @Override
316     @MainThread
onFinishedGoingToSleep()317     public void onFinishedGoingToSleep() {
318         mPrimaryBouncerInteractor.hide();
319     }
320 
321     @Override
322     @MainThread
setOccluded(boolean occluded, boolean animate)323     public void setOccluded(boolean occluded, boolean animate) {
324         mKeyguardStateController.notifyKeyguardState(
325                 mKeyguardStateController.isShowing(), occluded);
326         getOverlayViewGlobalStateController().setOccluded(occluded);
327         if (occluded) {
328             mCarSystemBarController.showAllOcclusionButtons(/* isSetup= */ true);
329         } else {
330             if (mShowing && isSecure()) {
331                 mCarSystemBarController.showAllKeyguardButtons(/* isSetup= */ true);
332             } else {
333                 mCarSystemBarController.showAllNavigationButtons(/* isSetUp= */ true);
334             }
335         }
336     }
337 
338     @Override
339     @MainThread
onCancelClicked()340     public void onCancelClicked() {
341         mPrimaryBouncerInteractor.hide();
342         mKeyguardCancelClickedListener.onCancelClicked();
343     }
344 
345     @Override
346     @MainThread
dismissAndCollapse()347     public void dismissAndCollapse() {
348         // If dismissing and collapsing Keyguard is requested (e.g. by a Keyguard-dismissing
349         // Activity) while Keyguard is occluded, unocclude Keyguard so the user can authenticate to
350         // dismiss Keyguard.
351         if (mKeyguardStateController.isOccluded()) {
352             setOccluded(/* occluded= */ false, /* animate= */ false);
353         }
354         if (!isSecure()) {
355             hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
356             resetBouncer();
357         }
358     }
359 
360     @Override
361     @MainThread
startPreHideAnimation(Runnable finishRunnable)362     public void startPreHideAnimation(Runnable finishRunnable) {
363         if (isBouncerShowing()) {
364             mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable);
365         } else if (finishRunnable != null) {
366             finishRunnable.run();
367         }
368     }
369 
370     @Override
setNeedsInput(boolean needsInput)371     public void setNeedsInput(boolean needsInput) {
372         getOverlayViewGlobalStateController().setWindowNeedsInput(needsInput);
373     }
374 
375     @Override
onStartedGoingToSleep()376     public void onStartedGoingToSleep() {
377         mIsSleeping = true;
378     }
379 
380     @Override
onStartedWakingUp()381     public void onStartedWakingUp() {
382         mIsSleeping = false;
383         reset(/* hideBouncerWhenShowing= */ false);
384     }
385 
386     /**
387      * Add listener for keyguard cancel clicked.
388      */
registerOnKeyguardCancelClickedListener( OnKeyguardCancelClickedListener keyguardCancelClickedListener)389     public void registerOnKeyguardCancelClickedListener(
390             OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
391         mKeyguardCancelClickedListener = keyguardCancelClickedListener;
392     }
393 
394     /**
395      * Remove listener for keyguard cancel clicked.
396      */
unregisterOnKeyguardCancelClickedListener( OnKeyguardCancelClickedListener keyguardCancelClickedListener)397     public void unregisterOnKeyguardCancelClickedListener(
398             OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
399         mKeyguardCancelClickedListener = null;
400     }
401 
402     @Override
getViewRootImpl()403     public ViewRootImpl getViewRootImpl() {
404         if (getLayout() == null) return null;
405         return ((View) getLayout().getParent()).getViewRootImpl();
406     }
407 
408     @Override
409     @MainThread
isBouncerShowing()410     public boolean isBouncerShowing() {
411         return mPrimaryBouncerInteractor.isFullyShowing();
412     }
413 
414     @Override
415     @MainThread
primaryBouncerIsOrWillBeShowing()416     public boolean primaryBouncerIsOrWillBeShowing() {
417         return mPrimaryBouncerInteractor.isFullyShowing()
418                 || mPrimaryBouncerInteractor.isInTransit();
419     }
420 
421     @Override
keyguardGoingAway()422     public void keyguardGoingAway() {
423         // no-op
424     }
425 
426     @Override
setKeyguardGoingAwayState(boolean isKeyguardGoingAway)427     public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) {
428         // no-op
429     }
430 
431     @Override
shouldDisableWindowAnimationsForUnlock()432     public boolean shouldDisableWindowAnimationsForUnlock() {
433         return false;
434     }
435 
436     @Override
isGoingToNotificationShade()437     public boolean isGoingToNotificationShade() {
438         return false;
439     }
440 
441     @Override
isUnlockWithWallpaper()442     public boolean isUnlockWithWallpaper() {
443         return false;
444     }
445 
446     @Override
isBouncerShowingOverDream()447     public boolean isBouncerShowingOverDream() {
448         return false;
449     }
450 
451     @Override
shouldSubtleWindowAnimationsForUnlock()452     public boolean shouldSubtleWindowAnimationsForUnlock() {
453         return false;
454     }
455 
456     @Override
blockPanelExpansionFromCurrentTouch()457     public void blockPanelExpansionFromCurrentTouch() {
458         // no-op
459     }
460 
461     @Override
registerCentralSurfaces( CentralSurfaces centralSurfaces, ShadeViewController shadeViewController, ShadeExpansionStateManager shadeExpansionStateManager, BiometricUnlockController biometricUnlockController, View notificationContainer, KeyguardBypassController bypassController)462     public void registerCentralSurfaces(
463             CentralSurfaces centralSurfaces,
464             ShadeViewController shadeViewController,
465             ShadeExpansionStateManager shadeExpansionStateManager,
466             BiometricUnlockController biometricUnlockController,
467             View notificationContainer,
468             KeyguardBypassController bypassController) {
469         // no-op
470     }
471 
472     /**
473      * Hides Keyguard so that the transitioning Bouncer can be hidden until it is prepared. To be
474      * called by {@link com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator}
475      * when a new user is selected.
476      */
hideKeyguardToPrepareBouncer()477     public void hideKeyguardToPrepareBouncer() {
478         getLayout().setVisibility(View.INVISIBLE);
479     }
480 
481     @Override
setAllowRotaryFocus(boolean allowRotaryFocus)482     public boolean setAllowRotaryFocus(boolean allowRotaryFocus) {
483         boolean changed = super.setAllowRotaryFocus(allowRotaryFocus);
484         if (changed && allowRotaryFocus && mBouncerView.getDelegate() != null) {
485             // Resume the view so it can regain focus
486             mBouncerView.getDelegate().resume();
487         }
488         return changed;
489     }
490 
revealKeyguardIfBouncerPrepared()491     private void revealKeyguardIfBouncerPrepared() {
492         int reattemptDelayMillis = 50;
493         Runnable revealKeyguard = () -> {
494             if (!mPrimaryBouncerInteractor.isInTransit() || !isSecure()) {
495                 if (mShowing) {
496                     // Only set the layout as visible if the keyguard should be showing
497                     showInternal();
498                 }
499             } else {
500                 if (DEBUG) {
501                     Log.d(TAG, "revealKeyguardIfBouncerPrepared: Bouncer is not prepared "
502                             + "yet so reattempting after " + reattemptDelayMillis + "ms.");
503                 }
504                 mMainExecutor.executeDelayed(this::revealKeyguardIfBouncerPrepared,
505                         reattemptDelayMillis);
506             }
507         };
508         mMainExecutor.execute(revealKeyguard);
509     }
510 
notifyKeyguardUpdateMonitor()511     private void notifyKeyguardUpdateMonitor() {
512         mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(
513                 primaryBouncerIsOrWillBeShowing(), isBouncerShowing());
514     }
515 
516     /**
517      * WARNING: This method might cause Binder calls.
518      */
isSecure()519     private boolean isSecure() {
520         return mKeyguardSecurityModel.getSecurityMode(
521                 KeyguardUpdateMonitor.getCurrentUser()) != KeyguardSecurityModel.SecurityMode.None;
522     }
523 
524 
resetBouncer()525     private void resetBouncer() {
526         mMainExecutor.execute(() -> {
527             hideInternal();
528             mPrimaryBouncerInteractor.hide();
529             mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
530             revealKeyguardIfBouncerPrepared();
531         });
532     }
533 
makeOverlayToast(int stringId)534     private void makeOverlayToast(int stringId) {
535         Resources res = mContext.getResources();
536 
537         SystemUIToast systemUIToast = mToastFactory.createToast(mContext,
538                 res.getString(stringId), mContext.getPackageName(), UserHandle.myUserId(),
539                 res.getConfiguration().orientation);
540 
541         if (systemUIToast == null) {
542             return;
543         }
544 
545         View toastView = systemUIToast.getView();
546 
547         WindowManager.LayoutParams params = new WindowManager.LayoutParams();
548         params.height = WindowManager.LayoutParams.WRAP_CONTENT;
549         params.width = WindowManager.LayoutParams.WRAP_CONTENT;
550         params.format = PixelFormat.TRANSLUCENT;
551         params.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
552         params.y = systemUIToast.getYOffset();
553 
554         int absGravity = Gravity.getAbsoluteGravity(systemUIToast.getGravity(),
555                 res.getConfiguration().getLayoutDirection());
556         params.gravity = absGravity;
557 
558         if ((absGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
559             params.horizontalWeight = TOAST_PARAMS_HORIZONTAL_WEIGHT;
560         }
561         if ((absGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
562             params.verticalWeight = TOAST_PARAMS_VERTICAL_WEIGHT;
563         }
564 
565         // Make FocusParkingView temporarily unfocusable so it does not steal the focus.
566         // If FocusParkingView is focusable, it first steals focus and then returns it to Pattern
567         // Lock, which causes the Toast to appear repeatedly.
568         mFocusParkingView.setFocusable(false);
569         mWindowManager.addView(toastView, params);
570 
571         Animator inAnimator = systemUIToast.getInAnimation();
572         if (inAnimator != null) {
573             inAnimator.start();
574         }
575 
576         mMainExecutor.executeDelayed(new Runnable() {
577             @Override
578             public void run() {
579                 Animator outAnimator = systemUIToast.getOutAnimation();
580                 if (outAnimator != null) {
581                     outAnimator.start();
582                     outAnimator.addListener(new AnimatorListenerAdapter() {
583                         @Override
584                         public void onAnimationEnd(Animator animator) {
585                             mWindowManager.removeViewImmediate(toastView);
586                             mFocusParkingView.setFocusable(true);
587                         }
588                     });
589                 } else {
590                     mFocusParkingView.setFocusable(true);
591                 }
592             }
593         }, mToastShowDurationMillisecond);
594     }
595 
596     /**
597      * Defines a callback for keyguard cancel button clicked listeners.
598      */
599     public interface OnKeyguardCancelClickedListener {
600         /**
601          * Called when keyguard cancel button is clicked.
602          */
onCancelClicked()603         void onCancelClicked();
604     }
605 }
606