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