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