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