LockPatternKeyguardView.java revision cfdd6242eb0c26373b9c57d2ad1ddc126708189e
1/* 2 * Copyright (C) 2007 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 17package com.android.internal.policy.impl; 18 19import com.android.internal.R; 20import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode; 21import com.android.internal.policy.IFaceLockCallback; 22import com.android.internal.policy.IFaceLockInterface; 23import com.android.internal.telephony.IccCard; 24import com.android.internal.widget.LockPatternUtils; 25import com.android.internal.widget.LockScreenWidgetCallback; 26import com.android.internal.widget.LockScreenWidgetInterface; 27import com.android.internal.widget.TransportControlView; 28 29import android.accounts.Account; 30import android.accounts.AccountManager; 31import android.accounts.AccountManagerCallback; 32import android.accounts.AccountManagerFuture; 33import android.accounts.AuthenticatorException; 34import android.accounts.OperationCanceledException; 35import android.app.AlertDialog; 36import android.app.admin.DevicePolicyManager; 37import android.content.ComponentName; 38import android.content.Context; 39import android.content.Intent; 40import android.content.res.Configuration; 41import android.content.res.Resources; 42import android.content.ServiceConnection; 43import android.graphics.Bitmap; 44import android.graphics.Canvas; 45import android.graphics.ColorFilter; 46import android.graphics.PixelFormat; 47import android.graphics.drawable.Drawable; 48import android.os.Bundle; 49import android.os.Handler; 50import android.os.Message; 51import android.os.IBinder; 52import android.os.RemoteException; 53import android.os.SystemClock; 54import android.os.SystemProperties; 55import android.telephony.TelephonyManager; 56import android.text.TextUtils; 57import android.util.Log; 58import android.util.Slog; 59import android.view.KeyEvent; 60import android.view.MotionEvent; 61import android.view.View; 62import android.view.WindowManager; 63import android.view.accessibility.AccessibilityManager; 64 65import java.io.IOException; 66 67 68/** 69 * The host view for all of the screens of the pattern unlock screen. There are 70 * two {@link Mode}s of operation, lock and unlock. This will show the appropriate 71 * screen, and listen for callbacks via 72 * {@link com.android.internal.policy.impl.KeyguardScreenCallback} 73 * from the current screen. 74 * 75 * This view, in turn, communicates back to 76 * {@link com.android.internal.policy.impl.KeyguardViewManager} 77 * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. 78 */ 79public class LockPatternKeyguardView extends KeyguardViewBase implements Handler.Callback { 80 81 private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000; 82 83 static final boolean DEBUG_CONFIGURATION = false; 84 85 // time after launching EmergencyDialer before the screen goes blank. 86 private static final int EMERGENCY_CALL_TIMEOUT = 10000; 87 88 // intent action for launching emergency dialer activity. 89 static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; 90 91 private static final boolean DEBUG = false; 92 private static final String TAG = "LockPatternKeyguardView"; 93 94 private final KeyguardUpdateMonitor mUpdateMonitor; 95 private final KeyguardWindowController mWindowController; 96 97 private View mLockScreen; 98 private View mUnlockScreen; 99 100 private boolean mScreenOn = false; 101 private boolean mEnableFallback = false; // assume no fallback UI until we know better 102 103 private boolean mShowLockBeforeUnlock = false; 104 105 // The following were added to support FaceLock 106 private IFaceLockInterface mFaceLockService; 107 private boolean mBoundToFaceLockService = false; 108 private View mFaceLockAreaView; 109 110 private boolean mFaceLockServiceRunning = false; 111 private final Object mFaceLockServiceRunningLock = new Object(); 112 113 private Handler mHandler; 114 private final int MSG_SHOW_FACELOCK_AREA_VIEW = 0; 115 private final int MSG_HIDE_FACELOCK_AREA_VIEW = 1; 116 117 // Long enough to stay black while dialer comes up 118 // Short enough to not be black if the user goes back immediately 119 private final int FACELOCK_VIEW_AREA_EMERGENCY_HIDE_TIMEOUT = 1000; 120 121 /** 122 * The current {@link KeyguardScreen} will use this to communicate back to us. 123 */ 124 KeyguardScreenCallback mKeyguardScreenCallback; 125 126 127 private boolean mRequiresSim; 128 129 130 /** 131 * Either a lock screen (an informational keyguard screen), or an unlock 132 * screen (a means for unlocking the device) is shown at any given time. 133 */ 134 enum Mode { 135 LockScreen, 136 UnlockScreen 137 } 138 139 /** 140 * The different types screens available for {@link Mode#UnlockScreen}. 141 * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() 142 */ 143 enum UnlockMode { 144 145 /** 146 * Unlock by drawing a pattern. 147 */ 148 Pattern, 149 150 /** 151 * Unlock by entering a sim pin. 152 */ 153 SimPin, 154 155 /** 156 * Unlock by entering a sim puk. 157 */ 158 SimPuk, 159 160 /** 161 * Unlock by entering an account's login and password. 162 */ 163 Account, 164 165 /** 166 * Unlock by entering a password or PIN 167 */ 168 Password, 169 170 /** 171 * Unknown (uninitialized) value 172 */ 173 Unknown 174 } 175 176 /** 177 * The current mode. 178 */ 179 private Mode mMode = Mode.LockScreen; 180 181 /** 182 * Keeps track of what mode the current unlock screen is (cached from most recent computation in 183 * {@link #getUnlockMode}). 184 */ 185 private UnlockMode mUnlockScreenMode = UnlockMode.Unknown; 186 187 private boolean mForgotPattern; 188 189 /** 190 * If true, it means we are in the process of verifying that the user 191 * can get past the lock screen per {@link #verifyUnlock()} 192 */ 193 private boolean mIsVerifyUnlockOnly = false; 194 195 196 /** 197 * Used to lookup the state of the lock pattern 198 */ 199 private final LockPatternUtils mLockPatternUtils; 200 201 /** 202 * The current configuration. 203 */ 204 private Configuration mConfiguration; 205 206 private Runnable mRecreateRunnable = new Runnable() { 207 public void run() { 208 updateScreen(mMode, true); 209 } 210 }; 211 212 private LockScreenWidgetCallback mWidgetCallback = new LockScreenWidgetCallback() { 213 public void userActivity(View self) { 214 mKeyguardScreenCallback.pokeWakelock(TRANSPORT_USERACTIVITY_TIMEOUT); 215 } 216 217 public void requestShow(View view) { 218 if (DEBUG) Log.v(TAG, "View " + view + " requested show transports"); 219 view.setVisibility(View.VISIBLE); 220 221 // TODO: examine all widgets to derive clock status 222 mUpdateMonitor.reportClockVisible(false); 223 } 224 225 public void requestHide(View view) { 226 if (DEBUG) Log.v(TAG, "View " + view + " requested hide transports"); 227 view.setVisibility(View.GONE); 228 229 // TODO: examine all widgets to derive clock status 230 mUpdateMonitor.reportClockVisible(true); 231 } 232 }; 233 234 /** 235 * @return Whether we are stuck on the lock screen because the sim is 236 * missing. 237 */ 238 private boolean stuckOnLockScreenBecauseSimMissing() { 239 return mRequiresSim 240 && (!mUpdateMonitor.isDeviceProvisioned()) 241 && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT || 242 mUpdateMonitor.getSimState() == IccCard.State.PERM_DISABLED); 243 } 244 245 /** 246 * @param context Used to inflate, and create views. 247 * @param updateMonitor Knows the state of the world, and passed along to each 248 * screen so they can use the knowledge, and also register for callbacks 249 * on dynamic information. 250 * @param lockPatternUtils Used to look up state of lock pattern. 251 */ 252 public LockPatternKeyguardView( 253 Context context, 254 KeyguardUpdateMonitor updateMonitor, 255 LockPatternUtils lockPatternUtils, 256 KeyguardWindowController controller) { 257 super(context); 258 259 mHandler = new Handler(this); 260 mConfiguration = context.getResources().getConfiguration(); 261 mEnableFallback = false; 262 mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); 263 mUpdateMonitor = updateMonitor; 264 mLockPatternUtils = lockPatternUtils; 265 mWindowController = controller; 266 267 mKeyguardScreenCallback = new KeyguardScreenCallback() { 268 269 public void goToLockScreen() { 270 mForgotPattern = false; 271 if (mIsVerifyUnlockOnly) { 272 // navigating away from unlock screen during verify mode means 273 // we are done and the user failed to authenticate. 274 mIsVerifyUnlockOnly = false; 275 getCallback().keyguardDone(false); 276 } else { 277 updateScreen(Mode.LockScreen, false); 278 } 279 } 280 281 public void goToUnlockScreen() { 282 final IccCard.State simState = mUpdateMonitor.getSimState(); 283 if (stuckOnLockScreenBecauseSimMissing() 284 || (simState == IccCard.State.PUK_REQUIRED 285 && !mLockPatternUtils.isPukUnlockScreenEnable())){ 286 // stuck on lock screen when sim missing or 287 // puk'd but puk unlock screen is disabled 288 return; 289 } 290 if (!isSecure()) { 291 getCallback().keyguardDone(true); 292 } else { 293 updateScreen(Mode.UnlockScreen, false); 294 } 295 } 296 297 public void forgotPattern(boolean isForgotten) { 298 if (mEnableFallback) { 299 mForgotPattern = isForgotten; 300 updateScreen(Mode.UnlockScreen, false); 301 } 302 } 303 304 public boolean isSecure() { 305 return LockPatternKeyguardView.this.isSecure(); 306 } 307 308 public boolean isVerifyUnlockOnly() { 309 return mIsVerifyUnlockOnly; 310 } 311 312 public void recreateMe(Configuration config) { 313 removeCallbacks(mRecreateRunnable); 314 post(mRecreateRunnable); 315 } 316 317 public void takeEmergencyCallAction() { 318 // FaceLock must be stopped if it is running when emergency call is pressed 319 stopAndUnbindFromFaceLock(); 320 321 // Delay hiding FaceLock area so unlock doesn't display while dialer is coming up 322 mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACELOCK_AREA_VIEW, 323 FACELOCK_VIEW_AREA_EMERGENCY_HIDE_TIMEOUT); 324 325 pokeWakelock(EMERGENCY_CALL_TIMEOUT); 326 if (TelephonyManager.getDefault().getCallState() 327 == TelephonyManager.CALL_STATE_OFFHOOK) { 328 mLockPatternUtils.resumeCall(); 329 } else { 330 Intent intent = new Intent(ACTION_EMERGENCY_DIAL); 331 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 332 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 333 getContext().startActivity(intent); 334 } 335 } 336 337 public void pokeWakelock() { 338 getCallback().pokeWakelock(); 339 } 340 341 public void pokeWakelock(int millis) { 342 getCallback().pokeWakelock(millis); 343 } 344 345 public void keyguardDone(boolean authenticated) { 346 getCallback().keyguardDone(authenticated); 347 } 348 349 public void keyguardDoneDrawing() { 350 // irrelevant to keyguard screen, they shouldn't be calling this 351 } 352 353 public void reportFailedUnlockAttempt() { 354 mUpdateMonitor.reportFailedAttempt(); 355 final int failedAttempts = mUpdateMonitor.getFailedAttempts(); 356 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts + 357 " (enableFallback=" + mEnableFallback + ")"); 358 359 final boolean usingPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() 360 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 361 362 final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager() 363 .getMaximumFailedPasswordsForWipe(null); 364 365 final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 366 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 367 368 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? 369 (failedAttemptsBeforeWipe - failedAttempts) 370 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction 371 372 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { 373 // If we reach this code, it means the user has installed a DevicePolicyManager 374 // that requests device wipe after N attempts. Once we get below the grace 375 // period, we'll post this dialog every time as a clear warning until the 376 // bombshell hits and the device is wiped. 377 if (remainingBeforeWipe > 0) { 378 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe); 379 } else { 380 // Too many attempts. The device will be wiped shortly. 381 Slog.i(TAG, "Too many unlock attempts; device will be wiped!"); 382 showWipeDialog(failedAttempts); 383 } 384 } else if (usingPattern && mEnableFallback) { 385 if (failedAttempts == failedAttemptWarning) { 386 showAlmostAtAccountLoginDialog(); 387 } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { 388 mLockPatternUtils.setPermanentlyLocked(true); 389 updateScreen(mMode, false); 390 } 391 } else { 392 final boolean showTimeout = 393 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0; 394 if (showTimeout) { 395 showTimeoutDialog(); 396 } 397 } 398 mLockPatternUtils.reportFailedPasswordAttempt(); 399 } 400 401 public boolean doesFallbackUnlockScreenExist() { 402 return mEnableFallback; 403 } 404 405 public void reportSuccessfulUnlockAttempt() { 406 mLockPatternUtils.reportSuccessfulPasswordAttempt(); 407 } 408 }; 409 410 /** 411 * We'll get key events the current screen doesn't use. see 412 * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} 413 */ 414 setFocusableInTouchMode(true); 415 setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 416 417 updateScreen(getInitialMode(), false); 418 maybeEnableFallback(context); 419 } 420 421 private class AccountAnalyzer implements AccountManagerCallback<Bundle> { 422 private final AccountManager mAccountManager; 423 private final Account[] mAccounts; 424 private int mAccountIndex; 425 426 private AccountAnalyzer(AccountManager accountManager) { 427 mAccountManager = accountManager; 428 mAccounts = accountManager.getAccountsByType("com.google"); 429 } 430 431 private void next() { 432 // if we are ready to enable the fallback or if we depleted the list of accounts 433 // then finish and get out 434 if (mEnableFallback || mAccountIndex >= mAccounts.length) { 435 if (mUnlockScreen == null) { 436 if (DEBUG) Log.w(TAG, "no unlock screen when trying to enable fallback"); 437 } else if (mUnlockScreen instanceof PatternUnlockScreen) { 438 ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); 439 } 440 return; 441 } 442 443 // lookup the confirmCredentials intent for the current account 444 mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null); 445 } 446 447 public void start() { 448 mEnableFallback = false; 449 mAccountIndex = 0; 450 next(); 451 } 452 453 public void run(AccountManagerFuture<Bundle> future) { 454 try { 455 Bundle result = future.getResult(); 456 if (result.getParcelable(AccountManager.KEY_INTENT) != null) { 457 mEnableFallback = true; 458 } 459 } catch (OperationCanceledException e) { 460 // just skip the account if we are unable to query it 461 } catch (IOException e) { 462 // just skip the account if we are unable to query it 463 } catch (AuthenticatorException e) { 464 // just skip the account if we are unable to query it 465 } finally { 466 mAccountIndex++; 467 next(); 468 } 469 } 470 } 471 472 private void maybeEnableFallback(Context context) { 473 // Ask the account manager if we have an account that can be used as a 474 // fallback in case the user forgets his pattern. 475 AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context)); 476 accountAnalyzer.start(); 477 } 478 479 480 // TODO: 481 // This overloaded method was added to workaround a race condition in the framework between 482 // notification for orientation changed, layout() and switching resources. This code attempts 483 // to avoid drawing the incorrect layout while things are in transition. The method can just 484 // be removed once the race condition is fixed. See bugs 2262578 and 2292713. 485 @Override 486 protected void dispatchDraw(Canvas canvas) { 487 if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime()); 488 super.dispatchDraw(canvas); 489 } 490 491 @Override 492 public void reset() { 493 mIsVerifyUnlockOnly = false; 494 mForgotPattern = false; 495 post(mRecreateRunnable); 496 } 497 498 @Override 499 public void onScreenTurnedOff() { 500 mScreenOn = false; 501 mForgotPattern = false; 502 if (mMode == Mode.LockScreen) { 503 ((KeyguardScreen) mLockScreen).onPause(); 504 } else { 505 ((KeyguardScreen) mUnlockScreen).onPause(); 506 } 507 508 // When screen is turned off, need to unbind from FaceLock service if using FaceLock 509 stopAndUnbindFromFaceLock(); 510 } 511 512 @Override 513 public void onScreenTurnedOn() { 514 mScreenOn = true; 515 show(); 516 517 // When screen is turned on, need to bind to FaceLock service if we are using FaceLock 518 // But only if not dealing with a call 519 if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE) { 520 bindToFaceLock(); 521 } else { 522 mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW); 523 } 524 } 525 526 @Override 527 public void show() { 528 if (mMode == Mode.LockScreen) { 529 ((KeyguardScreen) mLockScreen).onResume(); 530 } else { 531 ((KeyguardScreen) mUnlockScreen).onResume(); 532 } 533 534 if (mLockPatternUtils.usingBiometricWeak()) { 535 mHandler.sendEmptyMessage(MSG_SHOW_FACELOCK_AREA_VIEW); 536 } else { 537 mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW); 538 } 539 } 540 541 private void recreateLockScreen() { 542 if (mLockScreen != null) { 543 ((KeyguardScreen) mLockScreen).onPause(); 544 ((KeyguardScreen) mLockScreen).cleanUp(); 545 removeView(mLockScreen); 546 } 547 548 mLockScreen = createLockScreen(); 549 mLockScreen.setVisibility(View.INVISIBLE); 550 addView(mLockScreen); 551 } 552 553 private void recreateUnlockScreen(UnlockMode unlockMode) { 554 if (mUnlockScreen != null) { 555 ((KeyguardScreen) mUnlockScreen).onPause(); 556 ((KeyguardScreen) mUnlockScreen).cleanUp(); 557 removeView(mUnlockScreen); 558 } 559 560 mUnlockScreen = createUnlockScreenFor(unlockMode); 561 mUnlockScreen.setVisibility(View.INVISIBLE); 562 addView(mUnlockScreen); 563 } 564 565 @Override 566 protected void onDetachedFromWindow() { 567 removeCallbacks(mRecreateRunnable); 568 569 // When view is hidden, need to unbind from FaceLock service if we are using FaceLock 570 // e.g., when device becomes unlocked 571 stopAndUnbindFromFaceLock(); 572 573 super.onDetachedFromWindow(); 574 } 575 576 protected void onConfigurationChanged(Configuration newConfig) { 577 Resources resources = getResources(); 578 mShowLockBeforeUnlock = resources.getBoolean(R.bool.config_enableLockBeforeUnlockScreen); 579 mConfiguration = newConfig; 580 if (DEBUG_CONFIGURATION) Log.v(TAG, "**** re-creating lock screen since config changed"); 581 removeCallbacks(mRecreateRunnable); 582 post(mRecreateRunnable); 583 } 584 585 @Override 586 protected boolean dispatchHoverEvent(MotionEvent event) { 587 // Do not let the screen to get locked while the user is disabled and touch 588 // exploring. A blind user will need significantly more time to find and 589 // interact with the lock screen views. 590 AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext); 591 if (accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled()) { 592 getCallback().pokeWakelock(); 593 } 594 return super.dispatchHoverEvent(event); 595 } 596 597 @Override 598 public void wakeWhenReadyTq(int keyCode) { 599 if (DEBUG) Log.d(TAG, "onWakeKey"); 600 if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) 601 && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) { 602 if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); 603 updateScreen(Mode.UnlockScreen, false); 604 getCallback().pokeWakelock(); 605 } else { 606 if (DEBUG) Log.d(TAG, "poking wake lock immediately"); 607 getCallback().pokeWakelock(); 608 } 609 } 610 611 @Override 612 public void verifyUnlock() { 613 if (!isSecure()) { 614 // non-secure keyguard screens are successfull by default 615 getCallback().keyguardDone(true); 616 } else if (mUnlockScreenMode != UnlockMode.Pattern 617 && mUnlockScreenMode != UnlockMode.Password) { 618 // can only verify unlock when in pattern/password mode 619 getCallback().keyguardDone(false); 620 } else { 621 // otherwise, go to the unlock screen, see if they can verify it 622 mIsVerifyUnlockOnly = true; 623 updateScreen(Mode.UnlockScreen, false); 624 } 625 } 626 627 @Override 628 public void cleanUp() { 629 if (mLockScreen != null) { 630 ((KeyguardScreen) mLockScreen).onPause(); 631 ((KeyguardScreen) mLockScreen).cleanUp(); 632 this.removeView(mLockScreen); 633 mLockScreen = null; 634 } 635 if (mUnlockScreen != null) { 636 ((KeyguardScreen) mUnlockScreen).onPause(); 637 ((KeyguardScreen) mUnlockScreen).cleanUp(); 638 this.removeView(mUnlockScreen); 639 mUnlockScreen = null; 640 } 641 } 642 643 private boolean isSecure() { 644 UnlockMode unlockMode = getUnlockMode(); 645 boolean secure = false; 646 switch (unlockMode) { 647 case Pattern: 648 secure = mLockPatternUtils.isLockPatternEnabled(); 649 break; 650 case SimPin: 651 secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED; 652 break; 653 case SimPuk: 654 secure = mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; 655 break; 656 case Account: 657 secure = true; 658 break; 659 case Password: 660 secure = mLockPatternUtils.isLockPasswordEnabled(); 661 break; 662 default: 663 throw new IllegalStateException("unknown unlock mode " + unlockMode); 664 } 665 return secure; 666 } 667 668 private void updateScreen(Mode mode, boolean force) { 669 670 if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode 671 + " last mode=" + mMode + ", force = " + force, new RuntimeException()); 672 673 mMode = mode; 674 675 // Re-create the lock screen if necessary 676 if (mode == Mode.LockScreen || mShowLockBeforeUnlock) { 677 if (force || mLockScreen == null) { 678 recreateLockScreen(); 679 } 680 } 681 682 // Re-create the unlock screen if necessary. This is primarily required to properly handle 683 // SIM state changes. This typically happens when this method is called by reset() 684 if (mode == Mode.UnlockScreen) { 685 final UnlockMode unlockMode = getUnlockMode(); 686 if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { 687 recreateUnlockScreen(unlockMode); 688 } 689 } 690 691 // visibleScreen should never be null 692 final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; 693 final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; 694 695 // do this before changing visibility so focus isn't requested before the input 696 // flag is set 697 mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); 698 699 if (DEBUG_CONFIGURATION) { 700 Log.v(TAG, "Gone=" + goneScreen); 701 Log.v(TAG, "Visible=" + visibleScreen); 702 } 703 704 if (mScreenOn) { 705 if (goneScreen != null && goneScreen.getVisibility() == View.VISIBLE) { 706 ((KeyguardScreen) goneScreen).onPause(); 707 } 708 if (visibleScreen.getVisibility() != View.VISIBLE) { 709 ((KeyguardScreen) visibleScreen).onResume(); 710 } 711 } 712 713 if (goneScreen != null) { 714 goneScreen.setVisibility(View.GONE); 715 } 716 visibleScreen.setVisibility(View.VISIBLE); 717 requestLayout(); 718 719 if (!visibleScreen.requestFocus()) { 720 throw new IllegalStateException("keyguard screen must be able to take " 721 + "focus when shown " + visibleScreen.getClass().getCanonicalName()); 722 } 723 } 724 725 View createLockScreen() { 726 View lockView = new LockScreen( 727 mContext, 728 mConfiguration, 729 mLockPatternUtils, 730 mUpdateMonitor, 731 mKeyguardScreenCallback); 732 initializeTransportControlView(lockView); 733 return lockView; 734 } 735 736 View createUnlockScreenFor(UnlockMode unlockMode) { 737 View unlockView = null; 738 739 if (DEBUG) Log.d(TAG, 740 "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); 741 742 if (unlockMode == UnlockMode.Pattern) { 743 PatternUnlockScreen view = new PatternUnlockScreen( 744 mContext, 745 mConfiguration, 746 mLockPatternUtils, 747 mUpdateMonitor, 748 mKeyguardScreenCallback, 749 mUpdateMonitor.getFailedAttempts()); 750 view.setEnableFallback(mEnableFallback); 751 unlockView = view; 752 } else if (unlockMode == UnlockMode.SimPuk) { 753 unlockView = new SimPukUnlockScreen( 754 mContext, 755 mConfiguration, 756 mUpdateMonitor, 757 mKeyguardScreenCallback, 758 mLockPatternUtils); 759 } else if (unlockMode == UnlockMode.SimPin) { 760 unlockView = new SimUnlockScreen( 761 mContext, 762 mConfiguration, 763 mUpdateMonitor, 764 mKeyguardScreenCallback, 765 mLockPatternUtils); 766 } else if (unlockMode == UnlockMode.Account) { 767 try { 768 unlockView = new AccountUnlockScreen( 769 mContext, 770 mConfiguration, 771 mUpdateMonitor, 772 mKeyguardScreenCallback, 773 mLockPatternUtils); 774 } catch (IllegalStateException e) { 775 Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" 776 + " (IAccountsService isn't available)"); 777 // TODO: Need a more general way to provide a 778 // platform-specific fallback UI here. 779 // For now, if we can't display the account login 780 // unlock UI, just bring back the regular "Pattern" unlock mode. 781 782 // (We do this by simply returning a regular UnlockScreen 783 // here. This means that the user will still see the 784 // regular pattern unlock UI, regardless of the value of 785 // mUnlockScreenMode or whether or not we're in the 786 // "permanently locked" state.) 787 return createUnlockScreenFor(UnlockMode.Pattern); 788 } 789 } else if (unlockMode == UnlockMode.Password) { 790 unlockView = new PasswordUnlockScreen( 791 mContext, 792 mConfiguration, 793 mLockPatternUtils, 794 mUpdateMonitor, 795 mKeyguardScreenCallback); 796 } else { 797 throw new IllegalArgumentException("unknown unlock mode " + unlockMode); 798 } 799 initializeTransportControlView(unlockView); 800 initializeFaceLockAreaView(unlockView); // Only shows view if FaceLock is enabled 801 802 mUnlockScreenMode = unlockMode; 803 return unlockView; 804 } 805 806 private void initializeTransportControlView(View view) { 807 com.android.internal.widget.TransportControlView tcv = 808 (TransportControlView) view.findViewById(R.id.transport); 809 if (tcv == null) { 810 if (DEBUG) Log.w(TAG, "Couldn't find transport control widget"); 811 } else { 812 mUpdateMonitor.reportClockVisible(true); 813 tcv.setVisibility(View.GONE); // hide tcv until we get the callback below to show it. 814 tcv.setCallback(mWidgetCallback); 815 } 816 } 817 818 /** 819 * Given the current state of things, what should be the initial mode of 820 * the lock screen (lock or unlock). 821 */ 822 private Mode getInitialMode() { 823 final IccCard.State simState = mUpdateMonitor.getSimState(); 824 if (stuckOnLockScreenBecauseSimMissing() || 825 (simState == IccCard.State.PUK_REQUIRED && 826 !mLockPatternUtils.isPukUnlockScreenEnable())) { 827 return Mode.LockScreen; 828 } else { 829 if (!isSecure() || mShowLockBeforeUnlock) { 830 return Mode.LockScreen; 831 } else { 832 return Mode.UnlockScreen; 833 } 834 } 835 } 836 837 /** 838 * Given the current state of things, what should the unlock screen be? 839 */ 840 private UnlockMode getUnlockMode() { 841 final IccCard.State simState = mUpdateMonitor.getSimState(); 842 UnlockMode currentMode; 843 if (simState == IccCard.State.PIN_REQUIRED) { 844 currentMode = UnlockMode.SimPin; 845 } else if (simState == IccCard.State.PUK_REQUIRED) { 846 currentMode = UnlockMode.SimPuk; 847 } else { 848 final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality(); 849 switch (mode) { 850 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 851 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 852 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 853 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 854 currentMode = UnlockMode.Password; 855 break; 856 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 857 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: 858 // "forgot pattern" button is only available in the pattern mode... 859 if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { 860 currentMode = UnlockMode.Account; 861 } else { 862 currentMode = UnlockMode.Pattern; 863 } 864 break; 865 default: 866 throw new IllegalStateException("Unknown unlock mode:" + mode); 867 } 868 } 869 return currentMode; 870 } 871 872 private void showDialog(String title, String message) { 873 final AlertDialog dialog = new AlertDialog.Builder(mContext) 874 .setTitle(title) 875 .setMessage(message) 876 .setNeutralButton(R.string.ok, null) 877 .create(); 878 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 879 dialog.show(); 880 } 881 882 private void showTimeoutDialog() { 883 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 884 int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message; 885 if (getUnlockMode() == UnlockMode.Password) { 886 if(mLockPatternUtils.getKeyguardStoredPasswordQuality() == 887 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { 888 messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message; 889 } else { 890 messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message; 891 } 892 } 893 String message = mContext.getString(messageId, mUpdateMonitor.getFailedAttempts(), 894 timeoutInSeconds); 895 896 showDialog(null, message); 897 } 898 899 private void showAlmostAtAccountLoginDialog() { 900 final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 901 final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 902 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 903 String message = mContext.getString(R.string.lockscreen_failed_attempts_almost_glogin, 904 count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); 905 showDialog(null, message); 906 } 907 908 private void showAlmostAtWipeDialog(int attempts, int remaining) { 909 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 910 String message = mContext.getString( 911 R.string.lockscreen_failed_attempts_almost_at_wipe, attempts, remaining); 912 showDialog(null, message); 913 } 914 915 private void showWipeDialog(int attempts) { 916 String message = mContext.getString( 917 R.string.lockscreen_failed_attempts_now_wiping, attempts); 918 showDialog(null, message); 919 } 920 921 /** 922 * Used to put wallpaper on the background of the lock screen. Centers it 923 * Horizontally and pins the bottom (assuming that the lock screen is aligned 924 * with the bottom, so the wallpaper should extend above the top into the 925 * status bar). 926 */ 927 static private class FastBitmapDrawable extends Drawable { 928 private Bitmap mBitmap; 929 private int mOpacity; 930 931 private FastBitmapDrawable(Bitmap bitmap) { 932 mBitmap = bitmap; 933 mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 934 } 935 936 @Override 937 public void draw(Canvas canvas) { 938 canvas.drawBitmap( 939 mBitmap, 940 (getBounds().width() - mBitmap.getWidth()) / 2, 941 (getBounds().height() - mBitmap.getHeight()), 942 null); 943 } 944 945 @Override 946 public int getOpacity() { 947 return mOpacity; 948 } 949 950 @Override 951 public void setAlpha(int alpha) { 952 } 953 954 @Override 955 public void setColorFilter(ColorFilter cf) { 956 } 957 958 @Override 959 public int getIntrinsicWidth() { 960 return mBitmap.getWidth(); 961 } 962 963 @Override 964 public int getIntrinsicHeight() { 965 return mBitmap.getHeight(); 966 } 967 968 @Override 969 public int getMinimumWidth() { 970 return mBitmap.getWidth(); 971 } 972 973 @Override 974 public int getMinimumHeight() { 975 return mBitmap.getHeight(); 976 } 977 } 978 979 // Everything below pertains to FaceLock - might want to separate this out 980 981 // Only pattern and pin unlock screens actually have a view for the FaceLock area, so it's not 982 // uncommon for it to not exist. But if it does exist, we need to make sure it's shown (hiding 983 // the fallback) if FaceLock is enabled, and make sure it's hidden (showing the unlock) if 984 // FaceLock is disabled 985 private void initializeFaceLockAreaView(View view) { 986 mFaceLockAreaView = view.findViewById(R.id.faceLockAreaView); 987 if (mFaceLockAreaView == null) { 988 if (DEBUG) Log.d(TAG, "Layout does not have faceLockAreaView"); 989 } 990 } 991 992 // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops 993 // This needs to be done in a handler because the call could be coming from a callback from the 994 // FaceLock service that is in a thread that can't modify the UI 995 @Override 996 public boolean handleMessage(Message msg) { 997 switch (msg.what) { 998 case MSG_SHOW_FACELOCK_AREA_VIEW: 999 mFaceLockAreaView.setVisibility(View.VISIBLE); 1000 break; 1001 case MSG_HIDE_FACELOCK_AREA_VIEW: 1002 mFaceLockAreaView.setVisibility(View.GONE); 1003 break; 1004 default: 1005 Log.w(TAG, "Unhandled message"); 1006 return false; 1007 } 1008 return true; 1009 } 1010 1011 // Binds to FaceLock service, but does not tell it to start 1012 public void bindToFaceLock() { 1013 if (mLockPatternUtils.usingBiometricWeak()) { 1014 if (!mBoundToFaceLockService) { 1015 if (DEBUG) Log.d(TAG, "before bind to FaceLock service"); 1016 mContext.bindService(new Intent(IFaceLockInterface.class.getName()), 1017 mFaceLockConnection, 1018 Context.BIND_AUTO_CREATE); 1019 if (DEBUG) Log.d(TAG, "after bind to FaceLock service"); 1020 mBoundToFaceLockService = true; 1021 } else { 1022 Log.w(TAG, "Attempt to bind to FaceLock when already bound"); 1023 } 1024 } 1025 } 1026 1027 // Tells FaceLock to stop and then unbinds from the FaceLock service 1028 public void stopAndUnbindFromFaceLock() { 1029 if (mLockPatternUtils.usingBiometricWeak()) { 1030 stopFaceLock(); 1031 1032 if (mBoundToFaceLockService) { 1033 if (DEBUG) Log.d(TAG, "before unbind from FaceLock service"); 1034 mContext.unbindService(mFaceLockConnection); 1035 if (DEBUG) Log.d(TAG, "after unbind from FaceLock service"); 1036 mBoundToFaceLockService = false; 1037 } else { 1038 // This could probably happen after the session when someone activates FaceLock 1039 // because it wasn't active when the phone was turned on 1040 Log.w(TAG, "Attempt to unbind from FaceLock when not bound"); 1041 } 1042 } 1043 } 1044 1045 private ServiceConnection mFaceLockConnection = new ServiceConnection() { 1046 // Completes connection, registers callback and starts FaceLock when service is bound 1047 @Override 1048 public void onServiceConnected(ComponentName className, IBinder iservice) { 1049 mFaceLockService = IFaceLockInterface.Stub.asInterface(iservice); 1050 if (DEBUG) Log.d(TAG, "Connected to FaceLock service"); 1051 try { 1052 mFaceLockService.registerCallback(mFaceLockCallback); 1053 } catch (RemoteException e) { 1054 throw new RuntimeException("Remote exception"); 1055 } 1056 1057 if (mFaceLockAreaView != null) { 1058 startFaceLock(mFaceLockAreaView.getWindowToken(), 1059 mFaceLockAreaView.getLeft(), mFaceLockAreaView.getTop(), 1060 mFaceLockAreaView.getWidth(), mFaceLockAreaView.getHeight()); 1061 } 1062 } 1063 1064 // Cleans up if FaceLock service unexpectedly disconnects 1065 @Override 1066 public void onServiceDisconnected(ComponentName className) { 1067 synchronized(mFaceLockServiceRunningLock) { 1068 mFaceLockService = null; 1069 mFaceLockServiceRunning = false; 1070 } 1071 Log.w(TAG, "Unexpected disconnect from FaceLock service"); 1072 } 1073 }; 1074 1075 // Tells the FaceLock service to start displaying its UI and perform recognition 1076 public void startFaceLock(IBinder windowToken, int x, int y, int h, int w) 1077 { 1078 if (mLockPatternUtils.usingBiometricWeak()) { 1079 synchronized (mFaceLockServiceRunningLock) { 1080 if (!mFaceLockServiceRunning) { 1081 if (DEBUG) Log.d(TAG, "Starting FaceLock"); 1082 try { 1083 mFaceLockService.startUi(windowToken, x, y, h, w); 1084 } catch (RemoteException e) { 1085 throw new RuntimeException("Remote exception"); 1086 } 1087 mFaceLockServiceRunning = true; 1088 } else { 1089 if (DEBUG) Log.w(TAG, "startFaceLock() attempted while running"); 1090 } 1091 } 1092 } 1093 } 1094 1095 // Tells the FaceLock service to stop displaying its UI and stop recognition 1096 public void stopFaceLock() 1097 { 1098 if (mLockPatternUtils.usingBiometricWeak()) { 1099 // Note that attempting to stop FaceLock when it's not running is not an issue. 1100 // FaceLock can return, which stops it and then we try to stop it when the 1101 // screen is turned off. That's why we check. 1102 synchronized (mFaceLockServiceRunningLock) { 1103 if (mFaceLockServiceRunning) { 1104 try { 1105 if (DEBUG) Log.d(TAG, "Stopping FaceLock"); 1106 mFaceLockService.stopUi(); 1107 } catch (RemoteException e) { 1108 throw new RuntimeException("Remote exception"); 1109 } 1110 mFaceLockServiceRunning = false; 1111 } 1112 } 1113 } 1114 } 1115 1116 // Implements the FaceLock service callback interface defined in AIDL 1117 private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() { 1118 1119 // Stops the FaceLock UI and indicates that the phone should be unlocked 1120 @Override 1121 public void unlock() { 1122 if (DEBUG) Log.d(TAG, "FaceLock unlock()"); 1123 mHandler.sendEmptyMessage(MSG_SHOW_FACELOCK_AREA_VIEW); // Keep fallback covered 1124 stopFaceLock(); 1125 1126 mKeyguardScreenCallback.keyguardDone(true); 1127 mKeyguardScreenCallback.reportSuccessfulUnlockAttempt(); 1128 } 1129 1130 // Stops the FaceLock UI and exposes the backup method without unlocking 1131 // This means either the user has cancelled out or FaceLock failed to recognize them 1132 @Override 1133 public void cancel() { 1134 if (DEBUG) Log.d(TAG, "FaceLock cancel()"); 1135 mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW); // Expose fallback 1136 stopFaceLock(); 1137 } 1138 }; 1139} 1140