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