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.keyguard; 18 19 import static android.app.StatusBarManager.SESSION_KEYGUARD; 20 21 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC; 22 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS; 23 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY; 24 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD; 25 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM; 26 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY; 27 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER; 28 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE; 29 import static com.android.systemui.DejankUtils.whitelistIpcs; 30 import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE; 31 import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES; 32 33 import android.app.ActivityManager; 34 import android.app.admin.DevicePolicyManager; 35 import android.content.Intent; 36 import android.content.res.ColorStateList; 37 import android.content.res.Resources; 38 import android.hardware.biometrics.BiometricOverlayConstants; 39 import android.media.AudioManager; 40 import android.metrics.LogMaker; 41 import android.os.SystemClock; 42 import android.os.UserHandle; 43 import android.telephony.TelephonyManager; 44 import android.text.TextUtils; 45 import android.util.Log; 46 import android.util.MathUtils; 47 import android.util.Slog; 48 import android.view.KeyEvent; 49 import android.view.MotionEvent; 50 import android.view.View; 51 import android.view.ViewTreeObserver; 52 import android.widget.FrameLayout; 53 import android.window.OnBackAnimationCallback; 54 55 import androidx.annotation.NonNull; 56 import androidx.annotation.Nullable; 57 58 import com.android.internal.annotations.VisibleForTesting; 59 import com.android.internal.logging.InstanceId; 60 import com.android.internal.logging.MetricsLogger; 61 import com.android.internal.logging.UiEventLogger; 62 import com.android.internal.logging.nano.MetricsProto; 63 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 64 import com.android.internal.widget.LockPatternUtils; 65 import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent; 66 import com.android.keyguard.KeyguardSecurityContainer.SwipeListener; 67 import com.android.keyguard.KeyguardSecurityModel.SecurityMode; 68 import com.android.keyguard.dagger.KeyguardBouncerScope; 69 import com.android.settingslib.utils.ThreadUtils; 70 import com.android.systemui.Gefingerpoken; 71 import com.android.systemui.R; 72 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor; 73 import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate; 74 import com.android.systemui.biometrics.SideFpsController; 75 import com.android.systemui.biometrics.SideFpsUiRequestSource; 76 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; 77 import com.android.systemui.classifier.FalsingA11yDelegate; 78 import com.android.systemui.classifier.FalsingCollector; 79 import com.android.systemui.flags.FeatureFlags; 80 import com.android.systemui.flags.Flags; 81 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; 82 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; 83 import com.android.systemui.log.SessionTracker; 84 import com.android.systemui.plugins.ActivityStarter; 85 import com.android.systemui.plugins.FalsingManager; 86 import com.android.systemui.shared.system.SysUiStatsLog; 87 import com.android.systemui.statusbar.policy.ConfigurationController; 88 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 89 import com.android.systemui.statusbar.policy.KeyguardStateController; 90 import com.android.systemui.statusbar.policy.UserSwitcherController; 91 import com.android.systemui.user.domain.interactor.UserInteractor; 92 import com.android.systemui.util.ViewController; 93 import com.android.systemui.util.kotlin.JavaAdapter; 94 import com.android.systemui.util.settings.GlobalSettings; 95 96 import java.io.File; 97 import java.util.Optional; 98 99 import javax.inject.Inject; 100 import javax.inject.Provider; 101 102 import kotlinx.coroutines.Job; 103 104 /** Controller for {@link KeyguardSecurityContainer} */ 105 @KeyguardBouncerScope 106 public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> 107 implements KeyguardSecurityView { 108 109 private static final boolean DEBUG = KeyguardConstants.DEBUG; 110 private static final String TAG = "KeyguardSecurityView"; 111 112 private final AdminSecondaryLockScreenController mAdminSecondaryLockScreenController; 113 private final LockPatternUtils mLockPatternUtils; 114 private final KeyguardUpdateMonitor mUpdateMonitor; 115 private final KeyguardSecurityModel mSecurityModel; 116 private final MetricsLogger mMetricsLogger; 117 private final UiEventLogger mUiEventLogger; 118 private final KeyguardStateController mKeyguardStateController; 119 private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; 120 private final ConfigurationController mConfigurationController; 121 private final FalsingCollector mFalsingCollector; 122 private final FalsingManager mFalsingManager; 123 private final UserSwitcherController mUserSwitcherController; 124 private final GlobalSettings mGlobalSettings; 125 private final FeatureFlags mFeatureFlags; 126 private final SessionTracker mSessionTracker; 127 private final Optional<SideFpsController> mSideFpsController; 128 private final FalsingA11yDelegate mFalsingA11yDelegate; 129 private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; 130 private final BouncerMessageInteractor mBouncerMessageInteractor; 131 private int mTranslationY; 132 private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; 133 // Whether the volume keys should be handled by keyguard. If true, then 134 // they will be handled here for specific media types such as music, otherwise 135 // the audio service will bring up the volume dialog. 136 private static final boolean KEYGUARD_MANAGES_VOLUME = false; 137 138 private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; 139 140 private final TelephonyManager mTelephonyManager; 141 private final ViewMediatorCallback mViewMediatorCallback; 142 private final AudioManager mAudioManager; 143 private View.OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event); 144 private ActivityStarter.OnDismissAction mDismissAction; 145 private Runnable mCancelAction; 146 private boolean mWillRunDismissFromKeyguard; 147 148 private int mLastOrientation; 149 150 private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid; 151 private int mCurrentUser = UserHandle.USER_NULL; 152 private UserSwitcherController.UserSwitchCallback mUserSwitchCallback = 153 new UserSwitcherController.UserSwitchCallback() { 154 @Override 155 public void onUserSwitched() { 156 if (mCurrentUser == KeyguardUpdateMonitor.getCurrentUser()) { 157 return; 158 } 159 mCurrentUser = KeyguardUpdateMonitor.getCurrentUser(); 160 showPrimarySecurityScreen(false); 161 reinflateViewFlipper((l) -> {}); 162 } 163 }; 164 165 @VisibleForTesting 166 final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() { 167 private MotionEvent mTouchDown; 168 @Override 169 public boolean onInterceptTouchEvent(MotionEvent ev) { 170 return false; 171 } 172 173 @Override 174 public boolean onTouchEvent(MotionEvent ev) { 175 // Do just a bit of our own falsing. People should only be tapping on the input, not 176 // swiping. 177 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 178 // If we're in one handed mode, the user can tap on the opposite side of the screen 179 // to move the bouncer across. In that case, inhibit the falsing (otherwise the taps 180 // to move the bouncer to each screen side can end up closing it instead). 181 if (mView.isTouchOnTheOtherSideOfSecurity(ev)) { 182 mFalsingCollector.avoidGesture(); 183 } 184 185 if (mTouchDown != null) { 186 mTouchDown.recycle(); 187 mTouchDown = null; 188 } 189 mTouchDown = MotionEvent.obtain(ev); 190 } else if (mTouchDown != null) { 191 if (ev.getActionMasked() == MotionEvent.ACTION_UP 192 || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) { 193 mTouchDown.recycle(); 194 mTouchDown = null; 195 } 196 } 197 return false; 198 } 199 }; 200 201 private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() { 202 203 @Override 204 public void onUserInput() { 205 mBouncerMessageInteractor.onPrimaryBouncerUserInput(); 206 mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput(); 207 mUpdateMonitor.cancelFaceAuth(); 208 } 209 210 @Override 211 public void dismiss(boolean authenticated, int targetId, 212 SecurityMode expectedSecurityMode) { 213 dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false, 214 expectedSecurityMode); 215 } 216 217 @Override 218 public boolean dismiss(boolean authenticated, int targetId, 219 boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { 220 return showNextSecurityScreenOrFinish( 221 authenticated, targetId, bypassSecondaryLockScreen, expectedSecurityMode); 222 } 223 224 @Override 225 public void userActivity() { 226 mViewMediatorCallback.userActivity(); 227 } 228 229 @Override 230 public boolean isVerifyUnlockOnly() { 231 return false; 232 } 233 234 @Override 235 public void onAttemptLockoutStart(long seconds) { 236 mBouncerMessageInteractor.onPrimaryAuthLockedOut(seconds); 237 } 238 239 @Override 240 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { 241 if (timeoutMs == 0 && !success) { 242 mBouncerMessageInteractor.onPrimaryAuthIncorrectAttempt(); 243 } 244 int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT; 245 if (mView.isSidedSecurityMode()) { 246 bouncerSide = mView.isSecurityLeftAligned() 247 ? SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__LEFT 248 : SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__RIGHT; 249 } 250 251 if (success) { 252 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, 253 SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS, 254 bouncerSide); 255 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId); 256 // Force a garbage collection in an attempt to erase any lockscreen password left in 257 // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard 258 // dismiss animation janky. 259 ThreadUtils.postOnBackgroundThread(() -> { 260 try { 261 Thread.sleep(5000); 262 } catch (InterruptedException ignored) { } 263 System.gc(); 264 System.runFinalization(); 265 System.gc(); 266 }); 267 } else { 268 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, 269 SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE, 270 bouncerSide); 271 reportFailedUnlockAttempt(userId, timeoutMs); 272 } 273 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER) 274 .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE)); 275 mUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS 276 : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE, getSessionId()); 277 } 278 279 @Override 280 public void reset() { 281 mViewMediatorCallback.resetKeyguard(); 282 } 283 284 @Override 285 public void onCancelClicked() { 286 mViewMediatorCallback.onCancelClicked(); 287 } 288 289 /** 290 * Authentication has happened and it's time to dismiss keyguard. This function 291 * should clean up and inform KeyguardViewMediator. 292 * 293 * @param fromPrimaryAuth whether the user has authenticated with primary auth like 294 * pattern, password or PIN but not by trust agents or fingerprint 295 * @param targetUserId a user that needs to be the foreground user at the dismissal 296 * completion. 297 */ 298 @Override 299 public void finish(boolean fromPrimaryAuth, int targetUserId) { 300 // If there's a pending runnable because the user interacted with a widget 301 // and we're leaving keyguard, then run it. 302 boolean deferKeyguardDone = false; 303 mWillRunDismissFromKeyguard = false; 304 if (mDismissAction != null) { 305 deferKeyguardDone = mDismissAction.onDismiss(); 306 mWillRunDismissFromKeyguard = mDismissAction.willRunAnimationOnKeyguard(); 307 mDismissAction = null; 308 mCancelAction = null; 309 } 310 if (mViewMediatorCallback != null) { 311 if (deferKeyguardDone) { 312 mViewMediatorCallback.keyguardDonePending(fromPrimaryAuth, targetUserId); 313 } else { 314 mViewMediatorCallback.keyguardDone(fromPrimaryAuth, targetUserId); 315 } 316 } 317 318 if (mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) { 319 mKeyguardTransitionInteractor.startDismissKeyguardTransition(); 320 } 321 } 322 323 @Override 324 public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) { 325 mViewMediatorCallback.setNeedsInput(needsInput); 326 } 327 }; 328 329 330 private final SwipeListener mSwipeListener = new SwipeListener() { 331 @Override 332 public void onSwipeUp() { 333 if (!mUpdateMonitor.isFaceDetectionRunning()) { 334 mKeyguardFaceAuthInteractor.onSwipeUpOnBouncer(); 335 boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth( 336 FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER); 337 mKeyguardSecurityCallback.userActivity(); 338 if (didFaceAuthRun) { 339 showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true); 340 } 341 } 342 if (mUpdateMonitor.isFaceEnrolled()) { 343 mUpdateMonitor.requestActiveUnlock( 344 ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT, 345 "swipeUpOnBouncer"); 346 } 347 } 348 349 @Override 350 public void onSwipeDown() { 351 mViewMediatorCallback.onBouncerSwipeDown(); 352 } 353 }; 354 private final ConfigurationController.ConfigurationListener mConfigurationListener = 355 new ConfigurationController.ConfigurationListener() { 356 @Override 357 public void onThemeChanged() { 358 reloadColors(); 359 } 360 361 @Override 362 public void onUiModeChanged() { 363 reloadColors(); 364 } 365 366 @Override 367 public void onDensityOrFontScaleChanged() { 368 KeyguardSecurityContainerController.this 369 .onDensityOrFontScaleOrOrientationChanged(); 370 } 371 372 @Override 373 public void onOrientationChanged(int orientation) { 374 if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) { 375 // TODO(b/295603468) 376 // Fix reinflation of views when flag is enabled. 377 KeyguardSecurityContainerController.this 378 .onDensityOrFontScaleOrOrientationChanged(); 379 } 380 } 381 }; 382 private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = 383 new KeyguardUpdateMonitorCallback() { 384 @Override 385 public void onTrustGrantedForCurrentUser( 386 boolean dismissKeyguard, 387 boolean newlyUnlocked, 388 TrustGrantFlags flags, 389 String message 390 ) { 391 if (dismissKeyguard) { 392 if (!mView.isVisibleToUser()) { 393 // The trust agent dismissed the keyguard without the user proving 394 // that they are present (by swiping up to show the bouncer). That's 395 // fine if the user proved presence via some other way to the trust 396 // agent. 397 Log.i(TAG, "TrustAgent dismissed Keyguard."); 398 } 399 mKeyguardSecurityCallback.dismiss( 400 false /* authenticated */, 401 KeyguardUpdateMonitor.getCurrentUser(), 402 /* bypassSecondaryLockScreen */ false, 403 SecurityMode.Invalid 404 ); 405 } else { 406 if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) { 407 mViewMediatorCallback.playTrustedSound(); 408 } 409 } 410 } 411 412 @Override 413 public void onDevicePolicyManagerStateChanged() { 414 showPrimarySecurityScreen(false); 415 } 416 }; 417 private final UserInteractor mUserInteractor; 418 private final Provider<AuthenticationInteractor> mAuthenticationInteractor; 419 private final Provider<JavaAdapter> mJavaAdapter; 420 private final DeviceProvisionedController mDeviceProvisionedController; 421 @Nullable private Job mSceneTransitionCollectionJob; 422 423 @Inject KeyguardSecurityContainerController(KeyguardSecurityContainer view, AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardSecurityModel keyguardSecurityModel, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, KeyguardStateController keyguardStateController, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController, FalsingCollector falsingCollector, FalsingManager falsingManager, UserSwitcherController userSwitcherController, FeatureFlags featureFlags, GlobalSettings globalSettings, SessionTracker sessionTracker, Optional<SideFpsController> sideFpsController, FalsingA11yDelegate falsingA11yDelegate, TelephonyManager telephonyManager, ViewMediatorCallback viewMediatorCallback, AudioManager audioManager, KeyguardFaceAuthInteractor keyguardFaceAuthInteractor, BouncerMessageInteractor bouncerMessageInteractor, Provider<JavaAdapter> javaAdapter, UserInteractor userInteractor, DeviceProvisionedController deviceProvisionedController, FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate, KeyguardTransitionInteractor keyguardTransitionInteractor, Provider<AuthenticationInteractor> authenticationInteractor )424 public KeyguardSecurityContainerController(KeyguardSecurityContainer view, 425 AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, 426 LockPatternUtils lockPatternUtils, 427 KeyguardUpdateMonitor keyguardUpdateMonitor, 428 KeyguardSecurityModel keyguardSecurityModel, 429 MetricsLogger metricsLogger, 430 UiEventLogger uiEventLogger, 431 KeyguardStateController keyguardStateController, 432 KeyguardSecurityViewFlipperController securityViewFlipperController, 433 ConfigurationController configurationController, 434 FalsingCollector falsingCollector, 435 FalsingManager falsingManager, 436 UserSwitcherController userSwitcherController, 437 FeatureFlags featureFlags, 438 GlobalSettings globalSettings, 439 SessionTracker sessionTracker, 440 Optional<SideFpsController> sideFpsController, 441 FalsingA11yDelegate falsingA11yDelegate, 442 TelephonyManager telephonyManager, 443 ViewMediatorCallback viewMediatorCallback, 444 AudioManager audioManager, 445 KeyguardFaceAuthInteractor keyguardFaceAuthInteractor, 446 BouncerMessageInteractor bouncerMessageInteractor, 447 Provider<JavaAdapter> javaAdapter, 448 UserInteractor userInteractor, 449 DeviceProvisionedController deviceProvisionedController, 450 FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate, 451 KeyguardTransitionInteractor keyguardTransitionInteractor, 452 Provider<AuthenticationInteractor> authenticationInteractor 453 ) { 454 super(view); 455 view.setAccessibilityDelegate(faceAuthAccessibilityDelegate); 456 mLockPatternUtils = lockPatternUtils; 457 mUpdateMonitor = keyguardUpdateMonitor; 458 mSecurityModel = keyguardSecurityModel; 459 mMetricsLogger = metricsLogger; 460 mUiEventLogger = uiEventLogger; 461 mKeyguardStateController = keyguardStateController; 462 mSecurityViewFlipperController = securityViewFlipperController; 463 mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create( 464 mKeyguardSecurityCallback); 465 mConfigurationController = configurationController; 466 mLastOrientation = getResources().getConfiguration().orientation; 467 mFalsingCollector = falsingCollector; 468 mFalsingManager = falsingManager; 469 mUserSwitcherController = userSwitcherController; 470 mFeatureFlags = featureFlags; 471 mGlobalSettings = globalSettings; 472 mSessionTracker = sessionTracker; 473 mSideFpsController = sideFpsController; 474 mFalsingA11yDelegate = falsingA11yDelegate; 475 mTelephonyManager = telephonyManager; 476 mViewMediatorCallback = viewMediatorCallback; 477 mAudioManager = audioManager; 478 mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; 479 mBouncerMessageInteractor = bouncerMessageInteractor; 480 mUserInteractor = userInteractor; 481 mAuthenticationInteractor = authenticationInteractor; 482 mJavaAdapter = javaAdapter; 483 mKeyguardTransitionInteractor = keyguardTransitionInteractor; 484 mDeviceProvisionedController = deviceProvisionedController; 485 } 486 487 @Override onInit()488 public void onInit() { 489 mSecurityViewFlipperController.init(); 490 updateResources(); 491 configureMode(); 492 } 493 494 @Override onViewAttached()495 protected void onViewAttached() { 496 mUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); 497 mView.setSwipeListener(mSwipeListener); 498 mView.addMotionEventListener(mGlobalTouchListener); 499 mConfigurationController.addCallback(mConfigurationListener); 500 mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback); 501 mView.setViewMediatorCallback(mViewMediatorCallback); 502 // Update ViewMediator with the current input method requirements 503 mViewMediatorCallback.setNeedsInput(needsInput()); 504 mView.setOnKeyListener(mOnKeyListener); 505 506 showPrimarySecurityScreen(false); 507 508 if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) { 509 // When the scene framework says that the lockscreen has been dismissed, dismiss the 510 // keyguard here, revealing the underlying app or launcher: 511 mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow( 512 mAuthenticationInteractor.get().isLockscreenDismissed(), 513 isLockscreenDismissed -> { 514 if (isLockscreenDismissed) { 515 final int selectedUserId = mUserInteractor.getSelectedUserId(); 516 showNextSecurityScreenOrFinish( 517 /* authenticated= */ true, 518 selectedUserId, 519 /* bypassSecondaryLockScreen= */ true, 520 mSecurityModel.getSecurityMode(selectedUserId)); 521 } 522 } 523 ); 524 } 525 } 526 527 @Override onViewDetached()528 protected void onViewDetached() { 529 mUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); 530 mConfigurationController.removeCallback(mConfigurationListener); 531 mView.removeMotionEventListener(mGlobalTouchListener); 532 mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback); 533 534 if (mSceneTransitionCollectionJob != null) { 535 mSceneTransitionCollectionJob.cancel(null); 536 mSceneTransitionCollectionJob = null; 537 } 538 } 539 540 /** */ onPause()541 public void onPause() { 542 if (DEBUG) { 543 Log.d(TAG, String.format("screen off, instance %s at %s", 544 Integer.toHexString(hashCode()), SystemClock.uptimeMillis())); 545 } 546 showPrimarySecurityScreen(true); 547 mAdminSecondaryLockScreenController.hide(); 548 if (mCurrentSecurityMode != SecurityMode.None) { 549 getCurrentSecurityController(controller -> controller.onPause()); 550 } 551 mView.onPause(); 552 mView.clearFocus(); 553 } 554 555 /** 556 * Shows and hides the side finger print sensor animation. 557 * 558 * @param isVisible sets whether we show or hide the side fps animation 559 */ updateSideFpsVisibility(boolean isVisible)560 public void updateSideFpsVisibility(boolean isVisible) { 561 if (!mSideFpsController.isPresent()) { 562 return; 563 } 564 565 if (isVisible) { 566 mSideFpsController.get().show( 567 SideFpsUiRequestSource.PRIMARY_BOUNCER, 568 BiometricOverlayConstants.REASON_AUTH_KEYGUARD 569 ); 570 } else { 571 mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); 572 } 573 } 574 575 /** 576 * Shows the primary security screen for the user. This will be either the multi-selector 577 * or the user's security method. 578 * @param turningOff true if the device is being turned off 579 */ showPrimarySecurityScreen(boolean turningOff)580 public void showPrimarySecurityScreen(boolean turningOff) { 581 if (DEBUG) Log.d(TAG, "show()"); 582 SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode( 583 KeyguardUpdateMonitor.getCurrentUser())); 584 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); 585 showSecurityScreen(securityMode); 586 } 587 588 /** 589 * Show a string explaining why the security view needs to be solved. 590 * 591 * @param reason a flag indicating which string should be shown, see 592 * {@link KeyguardSecurityView#PROMPT_REASON_NONE}, 593 * {@link KeyguardSecurityView#PROMPT_REASON_RESTART}, 594 * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and 595 * {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}. 596 */ 597 @Override showPromptReason(int reason)598 public void showPromptReason(int reason) { 599 if (mCurrentSecurityMode != SecurityMode.None) { 600 if (reason != PROMPT_REASON_NONE) { 601 Log.i(TAG, "Strong auth required, reason: " + reason); 602 } 603 getCurrentSecurityController(controller -> controller.showPromptReason(reason)); 604 } 605 } 606 607 /** Set message of bouncer title. */ showMessage(CharSequence message, ColorStateList colorState, boolean animated)608 public void showMessage(CharSequence message, ColorStateList colorState, boolean animated) { 609 if (mCurrentSecurityMode != SecurityMode.None) { 610 getCurrentSecurityController( 611 controller -> controller.showMessage(message, colorState, animated)); 612 } 613 } 614 615 /** 616 * Sets an action to run when keyguard finishes. 617 * 618 * @param action callback to be invoked when keyguard disappear animation completes. 619 */ setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction)620 public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) { 621 if (mCancelAction != null) { 622 mCancelAction.run(); 623 } 624 mDismissAction = action; 625 mCancelAction = cancelAction; 626 } 627 628 /** 629 * @return whether dismiss action or cancel action has been set. 630 */ hasDismissActions()631 public boolean hasDismissActions() { 632 return mDismissAction != null || mCancelAction != null; 633 } 634 635 /** 636 * @return will the dismissal run from the keyguard layout (instead of from bouncer) 637 */ willRunDismissFromKeyguard()638 public boolean willRunDismissFromKeyguard() { 639 return mWillRunDismissFromKeyguard; 640 } 641 642 /** 643 * Remove any dismiss action or cancel action that was set. 644 */ cancelDismissAction()645 public void cancelDismissAction() { 646 setOnDismissAction(null, null); 647 } 648 649 /** 650 * Potentially dismiss the current security screen, after validating that all device 651 * security has been unlocked. Otherwise show the next screen. 652 */ dismiss(boolean authenticated, int targetUserId, SecurityMode expectedSecurityMode)653 public void dismiss(boolean authenticated, int targetUserId, 654 SecurityMode expectedSecurityMode) { 655 mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode); 656 } 657 658 /** 659 * Dismisses the keyguard by going to the next screen or making it gone. 660 * @param targetUserId a user that needs to be the foreground user at the dismissal completion. 661 * @return True if the keyguard is done. 662 */ dismiss(int targetUserId)663 public boolean dismiss(int targetUserId) { 664 return mKeyguardSecurityCallback.dismiss(false, targetUserId, false, 665 getCurrentSecurityMode()); 666 } 667 getCurrentSecurityMode()668 public SecurityMode getCurrentSecurityMode() { 669 return mCurrentSecurityMode; 670 } 671 672 /** 673 * @return the top of the corresponding view. 674 */ getTop()675 public int getTop() { 676 int top = mView.getTop(); 677 // The password view has an extra top padding that should be ignored. 678 if (getCurrentSecurityMode() == SecurityMode.Password) { 679 View messageArea = mView.findViewById(R.id.keyguard_message_area); 680 top += messageArea.getTop(); 681 } 682 return top; 683 } 684 685 /** Set true if the view can be interacted with */ setInteractable(boolean isInteractable)686 public void setInteractable(boolean isInteractable) { 687 mView.setInteractable(isInteractable); 688 } 689 690 /** 691 * Dismiss keyguard due to a user unlock event. 692 */ finish(boolean primaryAuth, int currentUser)693 public void finish(boolean primaryAuth, int currentUser) { 694 mKeyguardSecurityCallback.finish(primaryAuth, currentUser); 695 } 696 697 /** 698 * @return the text of the KeyguardMessageArea. 699 */ getTitle()700 public CharSequence getTitle() { 701 return mView.getTitle(); 702 } 703 704 /** 705 * Resets the state of the views. 706 */ reset()707 public void reset() { 708 mView.reset(); 709 mSecurityViewFlipperController.reset(); 710 } 711 712 /** Prepares views in the bouncer before starting appear animation. */ prepareToShow()713 public void prepareToShow() { 714 View bouncerUserSwitcher = mView.findViewById(R.id.keyguard_bouncer_user_switcher); 715 if (bouncerUserSwitcher != null) { 716 bouncerUserSwitcher.setAlpha(0f); 717 } 718 } 719 720 @Override onResume(int reason)721 public void onResume(int reason) { 722 if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); 723 mView.requestFocus(); 724 if (mCurrentSecurityMode != SecurityMode.None) { 725 int state = SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN; 726 if (mView.isSidedSecurityMode()) { 727 state = mView.isSecurityLeftAligned() 728 ? SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN_LEFT 729 : SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN_RIGHT; 730 } 731 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, state); 732 733 734 getCurrentSecurityController(controller -> controller.onResume(reason)); 735 } 736 mView.onResume( 737 mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()), 738 mKeyguardStateController.isFaceAuthEnabled()); 739 } 740 741 /** Sets an initial message that would override the default message */ setInitialMessage()742 public void setInitialMessage() { 743 CharSequence customMessage = mViewMediatorCallback.consumeCustomMessage(); 744 if (!TextUtils.isEmpty(customMessage)) { 745 showMessage(customMessage, /* colorState= */ null, /* animated= */ false); 746 return; 747 } 748 showPromptReason(mViewMediatorCallback.getBouncerPromptReason()); 749 } 750 751 /** 752 * Show the bouncer and start appear animations. 753 * 754 */ appear()755 public void appear() { 756 // We might still be collapsed and the view didn't have time to layout yet or still 757 // be small, let's wait on the predraw to do the animation in that case. 758 mView.getViewTreeObserver().addOnPreDrawListener( 759 new ViewTreeObserver.OnPreDrawListener() { 760 @Override 761 public boolean onPreDraw() { 762 mView.getViewTreeObserver().removeOnPreDrawListener(this); 763 startAppearAnimation(); 764 return true; 765 } 766 }); 767 mView.requestLayout(); 768 } 769 startAppearAnimation()770 public void startAppearAnimation() { 771 if (mCurrentSecurityMode != SecurityMode.None) { 772 mView.startAppearAnimation(mCurrentSecurityMode); 773 getCurrentSecurityController(controller -> controller.startAppearAnimation()); 774 } 775 } 776 777 /** Set the alpha of the security container view */ setAlpha(float alpha)778 public void setAlpha(float alpha) { 779 mView.setAlpha(alpha); 780 } 781 startDisappearAnimation(Runnable onFinishRunnable)782 public boolean startDisappearAnimation(Runnable onFinishRunnable) { 783 if (mCurrentSecurityMode != SecurityMode.None) { 784 mView.startDisappearAnimation(mCurrentSecurityMode); 785 getCurrentSecurityController( 786 controller -> { 787 boolean didRunAnimation = controller.startDisappearAnimation( 788 onFinishRunnable); 789 if (!didRunAnimation && onFinishRunnable != null) { 790 onFinishRunnable.run(); 791 } 792 }); 793 } 794 return true; 795 } 796 onStartingToHide()797 public void onStartingToHide() { 798 if (mCurrentSecurityMode != SecurityMode.None) { 799 getCurrentSecurityController(controller -> controller.onStartingToHide()); 800 } 801 } 802 803 /** Called when the bouncer changes visibility. */ onBouncerVisibilityChanged(boolean isVisible)804 public void onBouncerVisibilityChanged(boolean isVisible) { 805 if (!isVisible) { 806 mView.resetScale(); 807 } 808 } 809 810 /** 811 * Shows the next security screen if there is one. 812 * @param authenticated true if the user entered the correct authentication 813 * @param targetUserId a user that needs to be the foreground user at the finish (if called) 814 * completion. 815 * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary 816 * secondary lock screen requirement, if any. 817 * @param expectedSecurityMode SecurityMode that is invoking this request. SecurityMode.Invalid 818 * indicates that no check should be done 819 * @return true if keyguard is done 820 */ showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode)821 public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, 822 boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { 823 824 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); 825 if (expectedSecurityMode != SecurityMode.Invalid 826 && expectedSecurityMode != getCurrentSecurityMode()) { 827 Log.w(TAG, "Attempted to invoke showNextSecurityScreenOrFinish with securityMode " 828 + expectedSecurityMode + ", but current mode is " + getCurrentSecurityMode()); 829 return false; 830 } 831 832 boolean finish = false; 833 boolean primaryAuth = false; 834 int eventSubtype = -1; 835 BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN; 836 if (mUpdateMonitor.getUserHasTrust(targetUserId)) { 837 finish = true; 838 eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS; 839 uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS; 840 } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) { 841 finish = true; 842 eventSubtype = BOUNCER_DISMISS_BIOMETRIC; 843 uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC; 844 } else if (SecurityMode.None == getCurrentSecurityMode()) { 845 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); 846 if (SecurityMode.None == securityMode) { 847 finish = true; // no security required 848 eventSubtype = BOUNCER_DISMISS_NONE_SECURITY; 849 uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY; 850 } else { 851 showSecurityScreen(securityMode); // switch to the alternate security view 852 } 853 } else if (authenticated) { 854 switch (getCurrentSecurityMode()) { 855 case Pattern: 856 case Password: 857 case PIN: 858 primaryAuth = true; 859 finish = true; 860 eventSubtype = BOUNCER_DISMISS_PASSWORD; 861 uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD; 862 break; 863 864 case SimPin: 865 case SimPuk: 866 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home 867 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); 868 boolean isLockscreenDisabled = mLockPatternUtils.isLockScreenDisabled( 869 KeyguardUpdateMonitor.getCurrentUser()) 870 || !mDeviceProvisionedController.isUserSetup(targetUserId); 871 872 if (securityMode == SecurityMode.None && isLockscreenDisabled) { 873 finish = true; 874 eventSubtype = BOUNCER_DISMISS_SIM; 875 uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM; 876 } else { 877 showSecurityScreen(securityMode); 878 } 879 break; 880 881 default: 882 Log.v(TAG, "Bad security screen " + getCurrentSecurityMode() 883 + ", fail safe"); 884 showPrimarySecurityScreen(false); 885 break; 886 } 887 } 888 // Check for device admin specified additional security measures. 889 if (finish && !bypassSecondaryLockScreen) { 890 Intent secondaryLockscreenIntent = 891 mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId); 892 if (secondaryLockscreenIntent != null) { 893 mAdminSecondaryLockScreenController.show(secondaryLockscreenIntent); 894 return false; 895 } 896 } 897 if (eventSubtype != -1) { 898 mMetricsLogger.write(new LogMaker(MetricsProto.MetricsEvent.BOUNCER) 899 .setType(MetricsProto.MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype)); 900 } 901 if (uiEvent != BouncerUiEvent.UNKNOWN) { 902 mUiEventLogger.log(uiEvent, getSessionId()); 903 } 904 if (finish) { 905 mKeyguardSecurityCallback.finish(primaryAuth, targetUserId); 906 } 907 return finish; 908 } 909 910 @Override needsInput()911 public boolean needsInput() { 912 return false; 913 } 914 915 /** 916 * @return the {@link OnBackAnimationCallback} to animate this view during a back gesture. 917 */ 918 @NonNull getBackCallback()919 public OnBackAnimationCallback getBackCallback() { 920 return mView.getBackCallback(); 921 } 922 923 /** 924 * @return whether we should dispatch the back key event before Ime. 925 */ dispatchBackKeyEventPreIme()926 public boolean dispatchBackKeyEventPreIme() { 927 return getCurrentSecurityMode() == SecurityMode.Password; 928 } 929 930 /** 931 * Allows the media keys to work when the keyguard is showing. 932 * The media keys should be of no interest to the actual keyguard view(s), 933 * so intercepting them here should not be of any harm. 934 * @param event The key event 935 * @return whether the event was consumed as a media key. 936 */ interceptMediaKey(KeyEvent event)937 public boolean interceptMediaKey(KeyEvent event) { 938 int keyCode = event.getKeyCode(); 939 if (event.getAction() == KeyEvent.ACTION_DOWN) { 940 switch (keyCode) { 941 case KeyEvent.KEYCODE_MEDIA_PLAY: 942 case KeyEvent.KEYCODE_MEDIA_PAUSE: 943 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 944 /* Suppress PLAY/PAUSE toggle when phone is ringing or 945 * in-call to avoid music playback */ 946 if (mTelephonyManager != null 947 && mTelephonyManager.getCallState() 948 != TelephonyManager.CALL_STATE_IDLE) { 949 return true; // suppress key event 950 } 951 return false; 952 case KeyEvent.KEYCODE_MUTE: 953 case KeyEvent.KEYCODE_HEADSETHOOK: 954 case KeyEvent.KEYCODE_MEDIA_STOP: 955 case KeyEvent.KEYCODE_MEDIA_NEXT: 956 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 957 case KeyEvent.KEYCODE_MEDIA_REWIND: 958 case KeyEvent.KEYCODE_MEDIA_RECORD: 959 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 960 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { 961 handleMediaKeyEvent(event); 962 return true; 963 } 964 965 case KeyEvent.KEYCODE_VOLUME_UP: 966 case KeyEvent.KEYCODE_VOLUME_DOWN: 967 case KeyEvent.KEYCODE_VOLUME_MUTE: { 968 if (KEYGUARD_MANAGES_VOLUME) { 969 // Volume buttons should only function for music (local or remote). 970 // TODO: Actually handle MUTE. 971 mAudioManager.adjustSuggestedStreamVolume( 972 keyCode == KeyEvent.KEYCODE_VOLUME_UP 973 ? AudioManager.ADJUST_RAISE 974 : AudioManager.ADJUST_LOWER /* direction */, 975 AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */); 976 // Don't execute default volume behavior 977 return true; 978 } else { 979 return false; 980 } 981 } 982 } 983 } else if (event.getAction() == KeyEvent.ACTION_UP) { 984 switch (keyCode) { 985 case KeyEvent.KEYCODE_MUTE: 986 case KeyEvent.KEYCODE_HEADSETHOOK: 987 case KeyEvent.KEYCODE_MEDIA_PLAY: 988 case KeyEvent.KEYCODE_MEDIA_PAUSE: 989 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 990 case KeyEvent.KEYCODE_MEDIA_STOP: 991 case KeyEvent.KEYCODE_MEDIA_NEXT: 992 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 993 case KeyEvent.KEYCODE_MEDIA_REWIND: 994 case KeyEvent.KEYCODE_MEDIA_RECORD: 995 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 996 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { 997 handleMediaKeyEvent(event); 998 return true; 999 } 1000 } 1001 } 1002 return false; 1003 } 1004 1005 handleMediaKeyEvent(KeyEvent keyEvent)1006 private void handleMediaKeyEvent(KeyEvent keyEvent) { 1007 mAudioManager.dispatchMediaKeyEvent(keyEvent); 1008 } 1009 1010 /** 1011 * In general, we enable unlocking the insecure keyguard with the menu key. However, there are 1012 * some cases where we wish to disable it, notably when the menu button placement or technology 1013 * is prone to false positives. 1014 * 1015 * @return true if the menu key should be enabled 1016 */ shouldEnableMenuKey()1017 public boolean shouldEnableMenuKey() { 1018 final Resources res = mView.getResources(); 1019 final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); 1020 final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); 1021 final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); 1022 return !configDisabled || isTestHarness || fileOverride; 1023 } 1024 1025 1026 /** 1027 * Switches to the given security view unless it's already being shown, in which case 1028 * this is a no-op. 1029 * 1030 * @param securityMode 1031 */ 1032 @VisibleForTesting showSecurityScreen(SecurityMode securityMode)1033 void showSecurityScreen(SecurityMode securityMode) { 1034 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); 1035 1036 if (securityMode == SecurityMode.Invalid || securityMode == mCurrentSecurityMode) { 1037 return; 1038 } 1039 1040 getCurrentSecurityController(oldView -> oldView.onPause()); 1041 1042 mCurrentSecurityMode = securityMode; 1043 1044 getCurrentSecurityController( 1045 newView -> { 1046 newView.onResume(KeyguardSecurityView.VIEW_REVEALED); 1047 mSecurityViewFlipperController.show(newView); 1048 configureMode(); 1049 mKeyguardSecurityCallback.onSecurityModeChanged( 1050 securityMode, newView != null && newView.needsInput()); 1051 1052 }); 1053 } 1054 1055 /** 1056 * Returns whether the given security view should be used in a "one handed" way. This can be 1057 * used to change how the security view is drawn (e.g. take up less of the screen, and align to 1058 * one side). 1059 */ canUseOneHandedBouncer()1060 private boolean canUseOneHandedBouncer() { 1061 if (!(mCurrentSecurityMode == SecurityMode.Pattern 1062 || mCurrentSecurityMode == SecurityMode.PIN)) { 1063 return false; 1064 } 1065 1066 return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); 1067 } 1068 canDisplayUserSwitcher()1069 private boolean canDisplayUserSwitcher() { 1070 return mFeatureFlags.isEnabled(Flags.BOUNCER_USER_SWITCHER); 1071 } 1072 configureMode()1073 private void configureMode() { 1074 boolean useSimSecurity = mCurrentSecurityMode == SecurityMode.SimPin 1075 || mCurrentSecurityMode == SecurityMode.SimPuk; 1076 int mode = KeyguardSecurityContainer.MODE_DEFAULT; 1077 if (canDisplayUserSwitcher() && !useSimSecurity) { 1078 mode = KeyguardSecurityContainer.MODE_USER_SWITCHER; 1079 } else if (canUseOneHandedBouncer()) { 1080 mode = KeyguardSecurityContainer.MODE_ONE_HANDED; 1081 } 1082 1083 mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController, 1084 () -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue), 1085 /* colorState= */ null, /* animated= */ true), mFalsingA11yDelegate); 1086 } 1087 reportFailedUnlockAttempt(int userId, int timeoutMs)1088 public void reportFailedUnlockAttempt(int userId, int timeoutMs) { 1089 // +1 for this time 1090 final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1; 1091 1092 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); 1093 1094 final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager(); 1095 final int failedAttemptsBeforeWipe = 1096 dpm.getMaximumFailedPasswordsForWipe(null, userId); 1097 1098 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 1099 ? (failedAttemptsBeforeWipe - failedAttempts) 1100 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction 1101 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { 1102 // The user has installed a DevicePolicyManager that requests a user/profile to be wiped 1103 // N attempts. Once we get below the grace period, we post this dialog every time as a 1104 // clear warning until the deletion fires. 1105 // Check which profile has the strictest policy for failed password attempts 1106 final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId); 1107 int userType = USER_TYPE_PRIMARY; 1108 if (expiringUser == userId) { 1109 // TODO: http://b/23522538 1110 if (expiringUser != UserHandle.USER_SYSTEM) { 1111 userType = USER_TYPE_SECONDARY_USER; 1112 } 1113 } else if (expiringUser != UserHandle.USER_NULL) { 1114 userType = USER_TYPE_WORK_PROFILE; 1115 } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY 1116 if (remainingBeforeWipe > 0) { 1117 mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType); 1118 } else { 1119 // Too many attempts. The device will be wiped shortly. 1120 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!"); 1121 mView.showWipeDialog(failedAttempts, userType); 1122 } 1123 } 1124 mLockPatternUtils.reportFailedPasswordAttempt(userId); 1125 if (timeoutMs > 0) { 1126 mLockPatternUtils.reportPasswordLockout(timeoutMs, userId); 1127 if (!mFeatureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) { 1128 mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils, 1129 mSecurityModel.getSecurityMode(userId)); 1130 } 1131 } 1132 } 1133 getCurrentSecurityController( KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback)1134 private void getCurrentSecurityController( 1135 KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback) { 1136 mSecurityViewFlipperController 1137 .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback, 1138 onViewInflatedCallback); 1139 } 1140 1141 /** 1142 * Apply keyguard configuration from the currently active resources. This can be called when the 1143 * device configuration changes, to re-apply some resources that are qualified on the device 1144 * configuration. 1145 */ updateResources()1146 public void updateResources() { 1147 int gravity; 1148 1149 Resources resources = mView.getResources(); 1150 1151 if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) { 1152 gravity = resources.getInteger( 1153 R.integer.keyguard_host_view_one_handed_gravity); 1154 } else { 1155 gravity = resources.getInteger(R.integer.keyguard_host_view_gravity); 1156 } 1157 1158 mTranslationY = resources 1159 .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y); 1160 // Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout. 1161 // We're just changing the gravity here though (which can't be applied to RelativeLayout), 1162 // so only attempt the update if mView is inside a FrameLayout. 1163 if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) { 1164 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams(); 1165 if (lp.gravity != gravity) { 1166 lp.gravity = gravity; 1167 mView.setLayoutParams(lp); 1168 } 1169 } 1170 1171 int newOrientation = getResources().getConfiguration().orientation; 1172 if (newOrientation != mLastOrientation) { 1173 mLastOrientation = newOrientation; 1174 configureMode(); 1175 } 1176 } 1177 getSessionId()1178 private @Nullable InstanceId getSessionId() { 1179 return mSessionTracker.getSessionId(SESSION_KEYGUARD); 1180 } 1181 1182 /** Update keyguard position based on a tapped X coordinate. */ updateKeyguardPosition(float x)1183 public void updateKeyguardPosition(float x) { 1184 mView.updatePositionByTouchX(x); 1185 } 1186 reloadColors()1187 private void reloadColors() { 1188 mView.reloadColors(); 1189 } 1190 1191 /** Handles density or font scale changes. */ onDensityOrFontScaleOrOrientationChanged()1192 private void onDensityOrFontScaleOrOrientationChanged() { 1193 reinflateViewFlipper(controller -> mView.onDensityOrFontScaleChanged()); 1194 } 1195 1196 /** 1197 * Reinflate the view flipper child view. 1198 */ reinflateViewFlipper( KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedListener)1199 public void reinflateViewFlipper( 1200 KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedListener) { 1201 mSecurityViewFlipperController.clearViews(); 1202 mSecurityViewFlipperController.asynchronouslyInflateView(mCurrentSecurityMode, 1203 mKeyguardSecurityCallback, onViewInflatedListener); 1204 } 1205 1206 /** 1207 * Fades and translates in/out the security screen. 1208 * Fades in as expansion approaches 0. 1209 * Animation duration is between 0.33f and 0.67f of panel expansion fraction. 1210 * @param fraction amount of the screen that should show. 1211 */ setExpansion(float fraction)1212 public void setExpansion(float fraction) { 1213 float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction); 1214 setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f)); 1215 mView.setTranslationY(scaledFraction * mTranslationY); 1216 } 1217 } 1218