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