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