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