1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.keyguard; 17 18 import android.app.Activity; 19 import android.app.AlertDialog; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.Context; 22 import android.content.res.ColorStateList; 23 import android.graphics.Rect; 24 import android.metrics.LogMaker; 25 import android.os.UserHandle; 26 import android.util.AttributeSet; 27 import android.util.Log; 28 import android.util.Slog; 29 import android.util.StatsLog; 30 import android.util.TypedValue; 31 import android.view.LayoutInflater; 32 import android.view.MotionEvent; 33 import android.view.VelocityTracker; 34 import android.view.View; 35 import android.view.ViewConfiguration; 36 import android.view.WindowManager; 37 import android.widget.FrameLayout; 38 39 import androidx.annotation.VisibleForTesting; 40 import androidx.dynamicanimation.animation.DynamicAnimation; 41 import androidx.dynamicanimation.animation.SpringAnimation; 42 43 import com.android.internal.logging.MetricsLogger; 44 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 45 import com.android.internal.widget.LockPatternUtils; 46 import com.android.keyguard.KeyguardSecurityModel.SecurityMode; 47 import com.android.systemui.Dependency; 48 import com.android.systemui.SystemUIFactory; 49 import com.android.systemui.util.InjectionInflationController; 50 51 public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView { 52 private static final boolean DEBUG = KeyguardConstants.DEBUG; 53 private static final String TAG = "KeyguardSecurityView"; 54 55 private static final int USER_TYPE_PRIMARY = 1; 56 private static final int USER_TYPE_WORK_PROFILE = 2; 57 private static final int USER_TYPE_SECONDARY_USER = 3; 58 59 // Bouncer is dismissed due to no security. 60 private static final int BOUNCER_DISMISS_NONE_SECURITY = 0; 61 // Bouncer is dismissed due to pin, password or pattern entered. 62 private static final int BOUNCER_DISMISS_PASSWORD = 1; 63 // Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated. 64 private static final int BOUNCER_DISMISS_BIOMETRIC = 2; 65 // Bouncer is dismissed due to extended access granted. 66 private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3; 67 // Bouncer is dismissed due to sim card unlock code entered. 68 private static final int BOUNCER_DISMISS_SIM = 4; 69 70 // Make the view move slower than the finger, as if the spring were applying force. 71 private static final float TOUCH_Y_MULTIPLIER = 0.25f; 72 // How much you need to drag the bouncer to trigger an auth retry (in dps.) 73 private static final float MIN_DRAG_SIZE = 10; 74 // How much to scale the default slop by, to avoid accidental drags. 75 private static final float SLOP_SCALE = 2f; 76 77 private KeyguardSecurityModel mSecurityModel; 78 private LockPatternUtils mLockPatternUtils; 79 80 private KeyguardSecurityViewFlipper mSecurityViewFlipper; 81 private boolean mIsVerifyUnlockOnly; 82 private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; 83 private KeyguardSecurityView mCurrentSecurityView; 84 private SecurityCallback mSecurityCallback; 85 private AlertDialog mAlertDialog; 86 private InjectionInflationController mInjectionInflationController; 87 private boolean mSwipeUpToRetry; 88 89 private final ViewConfiguration mViewConfiguration; 90 private final SpringAnimation mSpringAnimation; 91 private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); 92 private final KeyguardUpdateMonitor mUpdateMonitor; 93 94 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); 95 private float mLastTouchY = -1; 96 private int mActivePointerId = -1; 97 private boolean mIsDragging; 98 private float mStartTouchY = -1; 99 100 // Used to notify the container when something interesting happens. 101 public interface SecurityCallback { dismiss(boolean authenticated, int targetUserId)102 public boolean dismiss(boolean authenticated, int targetUserId); userActivity()103 public void userActivity(); onSecurityModeChanged(SecurityMode securityMode, boolean needsInput)104 public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); 105 106 /** 107 * @param strongAuth wheher the user has authenticated with strong authentication like 108 * pattern, password or PIN but not by trust agents or fingerprint 109 * @param targetUserId a user that needs to be the foreground user at the finish completion. 110 */ finish(boolean strongAuth, int targetUserId)111 public void finish(boolean strongAuth, int targetUserId); reset()112 public void reset(); onCancelClicked()113 public void onCancelClicked(); 114 } 115 KeyguardSecurityContainer(Context context, AttributeSet attrs)116 public KeyguardSecurityContainer(Context context, AttributeSet attrs) { 117 this(context, attrs, 0); 118 } 119 KeyguardSecurityContainer(Context context)120 public KeyguardSecurityContainer(Context context) { 121 this(context, null, 0); 122 } 123 KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle)124 public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { 125 super(context, attrs, defStyle); 126 mSecurityModel = new KeyguardSecurityModel(context); 127 mLockPatternUtils = new LockPatternUtils(context); 128 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); 129 mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); 130 mInjectionInflationController = new InjectionInflationController( 131 SystemUIFactory.getInstance().getRootComponent()); 132 mViewConfiguration = ViewConfiguration.get(context); 133 } 134 setSecurityCallback(SecurityCallback callback)135 public void setSecurityCallback(SecurityCallback callback) { 136 mSecurityCallback = callback; 137 } 138 139 @Override onResume(int reason)140 public void onResume(int reason) { 141 if (mCurrentSecuritySelection != SecurityMode.None) { 142 getSecurityView(mCurrentSecuritySelection).onResume(reason); 143 } 144 updateBiometricRetry(); 145 } 146 147 @Override onPause()148 public void onPause() { 149 if (mAlertDialog != null) { 150 mAlertDialog.dismiss(); 151 mAlertDialog = null; 152 } 153 if (mCurrentSecuritySelection != SecurityMode.None) { 154 getSecurityView(mCurrentSecuritySelection).onPause(); 155 } 156 } 157 158 @Override shouldDelayChildPressedState()159 public boolean shouldDelayChildPressedState() { 160 return true; 161 } 162 163 @Override onInterceptTouchEvent(MotionEvent event)164 public boolean onInterceptTouchEvent(MotionEvent event) { 165 switch (event.getActionMasked()) { 166 case MotionEvent.ACTION_DOWN: 167 int pointerIndex = event.getActionIndex(); 168 mStartTouchY = event.getY(pointerIndex); 169 mActivePointerId = event.getPointerId(pointerIndex); 170 mVelocityTracker.clear(); 171 break; 172 case MotionEvent.ACTION_MOVE: 173 if (mIsDragging) { 174 return true; 175 } 176 if (!mSwipeUpToRetry) { 177 return false; 178 } 179 // Avoid dragging the pattern view 180 if (mCurrentSecurityView.disallowInterceptTouch(event)) { 181 return false; 182 } 183 int index = event.findPointerIndex(mActivePointerId); 184 float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE; 185 if (mCurrentSecurityView != null && index != -1 186 && mStartTouchY - event.getY(index) > touchSlop) { 187 mIsDragging = true; 188 return true; 189 } 190 break; 191 case MotionEvent.ACTION_CANCEL: 192 case MotionEvent.ACTION_UP: 193 mIsDragging = false; 194 break; 195 } 196 return false; 197 } 198 199 @Override onTouchEvent(MotionEvent event)200 public boolean onTouchEvent(MotionEvent event) { 201 final int action = event.getActionMasked(); 202 switch (action) { 203 case MotionEvent.ACTION_MOVE: 204 mVelocityTracker.addMovement(event); 205 int pointerIndex = event.findPointerIndex(mActivePointerId); 206 float y = event.getY(pointerIndex); 207 if (mLastTouchY != -1) { 208 float dy = y - mLastTouchY; 209 setTranslationY(getTranslationY() + dy * TOUCH_Y_MULTIPLIER); 210 } 211 mLastTouchY = y; 212 break; 213 case MotionEvent.ACTION_UP: 214 case MotionEvent.ACTION_CANCEL: 215 mActivePointerId = -1; 216 mLastTouchY = -1; 217 mIsDragging = false; 218 startSpringAnimation(mVelocityTracker.getYVelocity()); 219 break; 220 case MotionEvent.ACTION_POINTER_UP: 221 int index = event.getActionIndex(); 222 int pointerId = event.getPointerId(index); 223 if (pointerId == mActivePointerId) { 224 // This was our active pointer going up. Choose a new 225 // active pointer and adjust accordingly. 226 final int newPointerIndex = index == 0 ? 1 : 0; 227 mLastTouchY = event.getY(newPointerIndex); 228 mActivePointerId = event.getPointerId(newPointerIndex); 229 } 230 break; 231 } 232 if (action == MotionEvent.ACTION_UP) { 233 if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 234 MIN_DRAG_SIZE, getResources().getDisplayMetrics())) { 235 mUpdateMonitor.requestFaceAuth(); 236 } 237 } 238 return true; 239 } 240 startSpringAnimation(float startVelocity)241 private void startSpringAnimation(float startVelocity) { 242 mSpringAnimation 243 .setStartVelocity(startVelocity) 244 .animateToFinalPosition(0); 245 } 246 startAppearAnimation()247 public void startAppearAnimation() { 248 if (mCurrentSecuritySelection != SecurityMode.None) { 249 getSecurityView(mCurrentSecuritySelection).startAppearAnimation(); 250 } 251 } 252 startDisappearAnimation(Runnable onFinishRunnable)253 public boolean startDisappearAnimation(Runnable onFinishRunnable) { 254 if (mCurrentSecuritySelection != SecurityMode.None) { 255 return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation( 256 onFinishRunnable); 257 } 258 return false; 259 } 260 261 /** 262 * Enables/disables swipe up to retry on the bouncer. 263 */ updateBiometricRetry()264 private void updateBiometricRetry() { 265 SecurityMode securityMode = getSecurityMode(); 266 int userId = KeyguardUpdateMonitor.getCurrentUser(); 267 mSwipeUpToRetry = mUpdateMonitor.isUnlockWithFacePossible(userId) 268 && securityMode != SecurityMode.SimPin 269 && securityMode != SecurityMode.SimPuk 270 && securityMode != SecurityMode.None; 271 } 272 getTitle()273 public CharSequence getTitle() { 274 return mSecurityViewFlipper.getTitle(); 275 } 276 getSecurityView(SecurityMode securityMode)277 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { 278 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 279 KeyguardSecurityView view = null; 280 final int children = mSecurityViewFlipper.getChildCount(); 281 for (int child = 0; child < children; child++) { 282 if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) { 283 view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child)); 284 break; 285 } 286 } 287 int layoutId = getLayoutIdFor(securityMode); 288 if (view == null && layoutId != 0) { 289 final LayoutInflater inflater = LayoutInflater.from(mContext); 290 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); 291 View v = mInjectionInflationController.injectable(inflater) 292 .inflate(layoutId, mSecurityViewFlipper, false); 293 mSecurityViewFlipper.addView(v); 294 updateSecurityView(v); 295 view = (KeyguardSecurityView)v; 296 view.reset(); 297 } 298 299 return view; 300 } 301 updateSecurityView(View view)302 private void updateSecurityView(View view) { 303 if (view instanceof KeyguardSecurityView) { 304 KeyguardSecurityView ksv = (KeyguardSecurityView) view; 305 ksv.setKeyguardCallback(mCallback); 306 ksv.setLockPatternUtils(mLockPatternUtils); 307 } else { 308 Log.w(TAG, "View " + view + " is not a KeyguardSecurityView"); 309 } 310 } 311 onFinishInflate()312 protected void onFinishInflate() { 313 mSecurityViewFlipper = findViewById(R.id.view_flipper); 314 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils); 315 } 316 setLockPatternUtils(LockPatternUtils utils)317 public void setLockPatternUtils(LockPatternUtils utils) { 318 mLockPatternUtils = utils; 319 mSecurityModel.setLockPatternUtils(utils); 320 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils); 321 } 322 323 @Override fitSystemWindows(Rect insets)324 protected boolean fitSystemWindows(Rect insets) { 325 // Consume bottom insets because we're setting the padding locally (for IME and navbar.) 326 setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), insets.bottom); 327 insets.bottom = 0; 328 return false; 329 } 330 showDialog(String title, String message)331 private void showDialog(String title, String message) { 332 if (mAlertDialog != null) { 333 mAlertDialog.dismiss(); 334 } 335 336 mAlertDialog = new AlertDialog.Builder(mContext) 337 .setTitle(title) 338 .setMessage(message) 339 .setCancelable(false) 340 .setNeutralButton(R.string.ok, null) 341 .create(); 342 if (!(mContext instanceof Activity)) { 343 mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 344 } 345 mAlertDialog.show(); 346 } 347 showTimeoutDialog(int userId, int timeoutMs)348 private void showTimeoutDialog(int userId, int timeoutMs) { 349 int timeoutInSeconds = (int) timeoutMs / 1000; 350 int messageId = 0; 351 352 switch (mSecurityModel.getSecurityMode(userId)) { 353 case Pattern: 354 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message; 355 break; 356 case PIN: 357 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message; 358 break; 359 case Password: 360 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message; 361 break; 362 // These don't have timeout dialogs. 363 case Invalid: 364 case None: 365 case SimPin: 366 case SimPuk: 367 break; 368 } 369 370 if (messageId != 0) { 371 final String message = mContext.getString(messageId, 372 mLockPatternUtils.getCurrentFailedPasswordAttempts(userId), 373 timeoutInSeconds); 374 showDialog(null, message); 375 } 376 } 377 showAlmostAtWipeDialog(int attempts, int remaining, int userType)378 private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { 379 String message = null; 380 switch (userType) { 381 case USER_TYPE_PRIMARY: 382 message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe, 383 attempts, remaining); 384 break; 385 case USER_TYPE_SECONDARY_USER: 386 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_user, 387 attempts, remaining); 388 break; 389 case USER_TYPE_WORK_PROFILE: 390 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_profile, 391 attempts, remaining); 392 break; 393 } 394 showDialog(null, message); 395 } 396 showWipeDialog(int attempts, int userType)397 private void showWipeDialog(int attempts, int userType) { 398 String message = null; 399 switch (userType) { 400 case USER_TYPE_PRIMARY: 401 message = mContext.getString(R.string.kg_failed_attempts_now_wiping, 402 attempts); 403 break; 404 case USER_TYPE_SECONDARY_USER: 405 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_user, 406 attempts); 407 break; 408 case USER_TYPE_WORK_PROFILE: 409 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_profile, 410 attempts); 411 break; 412 } 413 showDialog(null, message); 414 } 415 reportFailedUnlockAttempt(int userId, int timeoutMs)416 private void reportFailedUnlockAttempt(int userId, int timeoutMs) { 417 // +1 for this time 418 final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1; 419 420 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); 421 422 final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager(); 423 final int failedAttemptsBeforeWipe = 424 dpm.getMaximumFailedPasswordsForWipe(null, userId); 425 426 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? 427 (failedAttemptsBeforeWipe - failedAttempts) 428 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction 429 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { 430 // The user has installed a DevicePolicyManager that requests a user/profile to be wiped 431 // N attempts. Once we get below the grace period, we post this dialog every time as a 432 // clear warning until the deletion fires. 433 // Check which profile has the strictest policy for failed password attempts 434 final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId); 435 int userType = USER_TYPE_PRIMARY; 436 if (expiringUser == userId) { 437 // TODO: http://b/23522538 438 if (expiringUser != UserHandle.USER_SYSTEM) { 439 userType = USER_TYPE_SECONDARY_USER; 440 } 441 } else if (expiringUser != UserHandle.USER_NULL) { 442 userType = USER_TYPE_WORK_PROFILE; 443 } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY 444 if (remainingBeforeWipe > 0) { 445 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType); 446 } else { 447 // Too many attempts. The device will be wiped shortly. 448 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!"); 449 showWipeDialog(failedAttempts, userType); 450 } 451 } 452 mLockPatternUtils.reportFailedPasswordAttempt(userId); 453 if (timeoutMs > 0) { 454 mLockPatternUtils.reportPasswordLockout(timeoutMs, userId); 455 showTimeoutDialog(userId, timeoutMs); 456 } 457 } 458 459 /** 460 * Shows the primary security screen for the user. This will be either the multi-selector 461 * or the user's security method. 462 * @param turningOff true if the device is being turned off 463 */ showPrimarySecurityScreen(boolean turningOff)464 void showPrimarySecurityScreen(boolean turningOff) { 465 SecurityMode securityMode = mSecurityModel.getSecurityMode( 466 KeyguardUpdateMonitor.getCurrentUser()); 467 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); 468 showSecurityScreen(securityMode); 469 } 470 471 /** 472 * Shows the next security screen if there is one. 473 * @param authenticated true if the user entered the correct authentication 474 * @param targetUserId a user that needs to be the foreground user at the finish (if called) 475 * completion. 476 * @return true if keyguard is done 477 */ showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId)478 boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) { 479 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); 480 boolean finish = false; 481 boolean strongAuth = false; 482 int eventSubtype = -1; 483 if (mUpdateMonitor.getUserHasTrust(targetUserId)) { 484 finish = true; 485 eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS; 486 } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) { 487 finish = true; 488 eventSubtype = BOUNCER_DISMISS_BIOMETRIC; 489 } else if (SecurityMode.None == mCurrentSecuritySelection) { 490 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); 491 if (SecurityMode.None == securityMode) { 492 finish = true; // no security required 493 eventSubtype = BOUNCER_DISMISS_NONE_SECURITY; 494 } else { 495 showSecurityScreen(securityMode); // switch to the alternate security view 496 } 497 } else if (authenticated) { 498 switch (mCurrentSecuritySelection) { 499 case Pattern: 500 case Password: 501 case PIN: 502 strongAuth = true; 503 finish = true; 504 eventSubtype = BOUNCER_DISMISS_PASSWORD; 505 break; 506 507 case SimPin: 508 case SimPuk: 509 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home 510 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); 511 if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled( 512 KeyguardUpdateMonitor.getCurrentUser())) { 513 finish = true; 514 eventSubtype = BOUNCER_DISMISS_SIM; 515 } else { 516 showSecurityScreen(securityMode); 517 } 518 break; 519 520 default: 521 Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe"); 522 showPrimarySecurityScreen(false); 523 break; 524 } 525 } 526 if (eventSubtype != -1) { 527 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER) 528 .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype)); 529 } 530 if (finish) { 531 mSecurityCallback.finish(strongAuth, targetUserId); 532 } 533 return finish; 534 } 535 536 /** 537 * Switches to the given security view unless it's already being shown, in which case 538 * this is a no-op. 539 * 540 * @param securityMode 541 */ showSecurityScreen(SecurityMode securityMode)542 private void showSecurityScreen(SecurityMode securityMode) { 543 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); 544 545 if (securityMode == mCurrentSecuritySelection) return; 546 547 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); 548 KeyguardSecurityView newView = getSecurityView(securityMode); 549 550 // Emulate Activity life cycle 551 if (oldView != null) { 552 oldView.onPause(); 553 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view 554 } 555 if (securityMode != SecurityMode.None) { 556 newView.onResume(KeyguardSecurityView.VIEW_REVEALED); 557 newView.setKeyguardCallback(mCallback); 558 } 559 560 // Find and show this child. 561 final int childCount = mSecurityViewFlipper.getChildCount(); 562 563 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 564 for (int i = 0; i < childCount; i++) { 565 if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) { 566 mSecurityViewFlipper.setDisplayedChild(i); 567 break; 568 } 569 } 570 571 mCurrentSecuritySelection = securityMode; 572 mCurrentSecurityView = newView; 573 mSecurityCallback.onSecurityModeChanged(securityMode, 574 securityMode != SecurityMode.None && newView.needsInput()); 575 } 576 getFlipper()577 private KeyguardSecurityViewFlipper getFlipper() { 578 for (int i = 0; i < getChildCount(); i++) { 579 View child = getChildAt(i); 580 if (child instanceof KeyguardSecurityViewFlipper) { 581 return (KeyguardSecurityViewFlipper) child; 582 } 583 } 584 return null; 585 } 586 587 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { 588 public void userActivity() { 589 if (mSecurityCallback != null) { 590 mSecurityCallback.userActivity(); 591 } 592 } 593 594 public void dismiss(boolean authenticated, int targetId) { 595 mSecurityCallback.dismiss(authenticated, targetId); 596 } 597 598 public boolean isVerifyUnlockOnly() { 599 return mIsVerifyUnlockOnly; 600 } 601 602 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { 603 if (success) { 604 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, 605 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS); 606 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId); 607 } else { 608 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, 609 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE); 610 KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs); 611 } 612 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER) 613 .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE)); 614 } 615 616 public void reset() { 617 mSecurityCallback.reset(); 618 } 619 620 public void onCancelClicked() { 621 mSecurityCallback.onCancelClicked(); 622 } 623 }; 624 625 // The following is used to ignore callbacks from SecurityViews that are no longer current 626 // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the 627 // state for the current security method. 628 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { 629 @Override 630 public void userActivity() { } 631 @Override 632 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { } 633 @Override 634 public boolean isVerifyUnlockOnly() { return false; } 635 @Override 636 public void dismiss(boolean securityVerified, int targetUserId) { } 637 @Override 638 public void reset() {} 639 }; 640 getSecurityViewIdForMode(SecurityMode securityMode)641 private int getSecurityViewIdForMode(SecurityMode securityMode) { 642 switch (securityMode) { 643 case Pattern: return R.id.keyguard_pattern_view; 644 case PIN: return R.id.keyguard_pin_view; 645 case Password: return R.id.keyguard_password_view; 646 case SimPin: return R.id.keyguard_sim_pin_view; 647 case SimPuk: return R.id.keyguard_sim_puk_view; 648 } 649 return 0; 650 } 651 652 @VisibleForTesting getLayoutIdFor(SecurityMode securityMode)653 public int getLayoutIdFor(SecurityMode securityMode) { 654 switch (securityMode) { 655 case Pattern: return R.layout.keyguard_pattern_view; 656 case PIN: return R.layout.keyguard_pin_view; 657 case Password: return R.layout.keyguard_password_view; 658 case SimPin: return R.layout.keyguard_sim_pin_view; 659 case SimPuk: return R.layout.keyguard_sim_puk_view; 660 default: 661 return 0; 662 } 663 } 664 getSecurityMode()665 public SecurityMode getSecurityMode() { 666 return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()); 667 } 668 getCurrentSecurityMode()669 public SecurityMode getCurrentSecurityMode() { 670 return mCurrentSecuritySelection; 671 } 672 getCurrentSecurityView()673 public KeyguardSecurityView getCurrentSecurityView() { 674 return mCurrentSecurityView; 675 } 676 verifyUnlock()677 public void verifyUnlock() { 678 mIsVerifyUnlockOnly = true; 679 showSecurityScreen(getSecurityMode()); 680 } 681 getCurrentSecuritySelection()682 public SecurityMode getCurrentSecuritySelection() { 683 return mCurrentSecuritySelection; 684 } 685 dismiss(boolean authenticated, int targetUserId)686 public void dismiss(boolean authenticated, int targetUserId) { 687 mCallback.dismiss(authenticated, targetUserId); 688 } 689 needsInput()690 public boolean needsInput() { 691 return mSecurityViewFlipper.needsInput(); 692 } 693 694 @Override setKeyguardCallback(KeyguardSecurityCallback callback)695 public void setKeyguardCallback(KeyguardSecurityCallback callback) { 696 mSecurityViewFlipper.setKeyguardCallback(callback); 697 } 698 699 @Override reset()700 public void reset() { 701 mSecurityViewFlipper.reset(); 702 } 703 704 @Override getCallback()705 public KeyguardSecurityCallback getCallback() { 706 return mSecurityViewFlipper.getCallback(); 707 } 708 709 @Override showPromptReason(int reason)710 public void showPromptReason(int reason) { 711 if (mCurrentSecuritySelection != SecurityMode.None) { 712 if (reason != PROMPT_REASON_NONE) { 713 Log.i(TAG, "Strong auth required, reason: " + reason); 714 } 715 getSecurityView(mCurrentSecuritySelection).showPromptReason(reason); 716 } 717 } 718 showMessage(CharSequence message, ColorStateList colorState)719 public void showMessage(CharSequence message, ColorStateList colorState) { 720 if (mCurrentSecuritySelection != SecurityMode.None) { 721 getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState); 722 } 723 } 724 725 @Override showUsabilityHint()726 public void showUsabilityHint() { 727 mSecurityViewFlipper.showUsabilityHint(); 728 } 729 730 } 731 732