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 17 package com.android.internal.policy.impl; 18 19 import com.android.internal.R; 20 import com.android.internal.telephony.IccCard; 21 import com.android.internal.widget.LockPatternUtils; 22 23 import android.accounts.Account; 24 import android.accounts.AccountManager; 25 import android.accounts.AccountManagerCallback; 26 import android.accounts.AccountManagerFuture; 27 import android.accounts.AuthenticatorException; 28 import android.accounts.OperationCanceledException; 29 import android.app.AlertDialog; 30 import android.app.admin.DevicePolicyManager; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.res.Configuration; 34 import android.graphics.Bitmap; 35 import android.graphics.Canvas; 36 import android.graphics.ColorFilter; 37 import android.graphics.PixelFormat; 38 import android.graphics.drawable.Drawable; 39 import android.os.Bundle; 40 import android.os.SystemClock; 41 import android.os.SystemProperties; 42 import android.telephony.TelephonyManager; 43 import android.text.TextUtils; 44 import android.util.Log; 45 import android.view.KeyEvent; 46 import android.view.View; 47 import android.view.WindowManager; 48 49 import java.io.IOException; 50 51 /** 52 * The host view for all of the screens of the pattern unlock screen. There are 53 * two {@link Mode}s of operation, lock and unlock. This will show the appropriate 54 * screen, and listen for callbacks via 55 * {@link com.android.internal.policy.impl.KeyguardScreenCallback} 56 * from the current screen. 57 * 58 * This view, in turn, communicates back to 59 * {@link com.android.internal.policy.impl.KeyguardViewManager} 60 * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. 61 */ 62 public class LockPatternKeyguardView extends KeyguardViewBase { 63 64 static final boolean DEBUG_CONFIGURATION = false; 65 66 // time after launching EmergencyDialer before the screen goes blank. 67 private static final int EMERGENCY_CALL_TIMEOUT = 10000; 68 69 // intent action for launching emergency dialer activity. 70 static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; 71 72 private static final boolean DEBUG = false; 73 private static final String TAG = "LockPatternKeyguardView"; 74 75 private final KeyguardUpdateMonitor mUpdateMonitor; 76 private final KeyguardWindowController mWindowController; 77 78 private View mLockScreen; 79 private View mUnlockScreen; 80 81 private boolean mScreenOn = false; 82 private boolean mEnableFallback = false; // assume no fallback UI until we know better 83 84 /** 85 * The current {@link KeyguardScreen} will use this to communicate back to us. 86 */ 87 KeyguardScreenCallback mKeyguardScreenCallback; 88 89 90 private boolean mRequiresSim; 91 92 93 /** 94 * Either a lock screen (an informational keyguard screen), or an unlock 95 * screen (a means for unlocking the device) is shown at any given time. 96 */ 97 enum Mode { 98 LockScreen, 99 UnlockScreen 100 } 101 102 /** 103 * The different types screens available for {@link Mode#UnlockScreen}. 104 * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() 105 */ 106 enum UnlockMode { 107 108 /** 109 * Unlock by drawing a pattern. 110 */ 111 Pattern, 112 113 /** 114 * Unlock by entering a sim pin. 115 */ 116 SimPin, 117 118 /** 119 * Unlock by entering an account's login and password. 120 */ 121 Account, 122 123 /** 124 * Unlock by entering a password or PIN 125 */ 126 Password, 127 128 /** 129 * Unknown (uninitialized) value 130 */ 131 Unknown 132 } 133 134 /** 135 * The current mode. 136 */ 137 private Mode mMode = Mode.LockScreen; 138 139 /** 140 * Keeps track of what mode the current unlock screen is (cached from most recent computation in 141 * {@link #getUnlockMode}). 142 */ 143 private UnlockMode mUnlockScreenMode; 144 145 private boolean mForgotPattern; 146 147 /** 148 * If true, it means we are in the process of verifying that the user 149 * can get past the lock screen per {@link #verifyUnlock()} 150 */ 151 private boolean mIsVerifyUnlockOnly = false; 152 153 154 /** 155 * Used to lookup the state of the lock pattern 156 */ 157 private final LockPatternUtils mLockPatternUtils; 158 159 private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown; 160 161 /** 162 * The current configuration. 163 */ 164 private Configuration mConfiguration; 165 166 /** 167 * @return Whether we are stuck on the lock screen because the sim is 168 * missing. 169 */ 170 private boolean stuckOnLockScreenBecauseSimMissing() { 171 return mRequiresSim 172 && (!mUpdateMonitor.isDeviceProvisioned()) 173 && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); 174 } 175 176 /** 177 * @param context Used to inflate, and create views. 178 * @param updateMonitor Knows the state of the world, and passed along to each 179 * screen so they can use the knowledge, and also register for callbacks 180 * on dynamic information. 181 * @param lockPatternUtils Used to look up state of lock pattern. 182 */ 183 public LockPatternKeyguardView( 184 Context context, 185 KeyguardUpdateMonitor updateMonitor, 186 LockPatternUtils lockPatternUtils, 187 KeyguardWindowController controller) { 188 super(context); 189 190 mConfiguration = context.getResources().getConfiguration(); 191 mEnableFallback = false; 192 193 mRequiresSim = 194 TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); 195 196 mUpdateMonitor = updateMonitor; 197 mLockPatternUtils = lockPatternUtils; 198 mWindowController = controller; 199 200 mMode = getInitialMode(); 201 202 mKeyguardScreenCallback = new KeyguardScreenCallback() { 203 204 public void goToLockScreen() { 205 mForgotPattern = false; 206 if (mIsVerifyUnlockOnly) { 207 // navigating away from unlock screen during verify mode means 208 // we are done and the user failed to authenticate. 209 mIsVerifyUnlockOnly = false; 210 getCallback().keyguardDone(false); 211 } else { 212 updateScreen(Mode.LockScreen); 213 } 214 } 215 216 public void goToUnlockScreen() { 217 final IccCard.State simState = mUpdateMonitor.getSimState(); 218 if (stuckOnLockScreenBecauseSimMissing() 219 || (simState == IccCard.State.PUK_REQUIRED)){ 220 // stuck on lock screen when sim missing or puk'd 221 return; 222 } 223 if (!isSecure()) { 224 getCallback().keyguardDone(true); 225 } else { 226 updateScreen(Mode.UnlockScreen); 227 } 228 } 229 230 public void forgotPattern(boolean isForgotten) { 231 if (mEnableFallback) { 232 mForgotPattern = isForgotten; 233 updateScreen(Mode.UnlockScreen); 234 } 235 } 236 237 public boolean isSecure() { 238 return LockPatternKeyguardView.this.isSecure(); 239 } 240 241 public boolean isVerifyUnlockOnly() { 242 return mIsVerifyUnlockOnly; 243 } 244 245 public void recreateMe(Configuration config) { 246 mConfiguration = config; 247 recreateScreens(); 248 } 249 250 public void takeEmergencyCallAction() { 251 pokeWakelock(EMERGENCY_CALL_TIMEOUT); 252 if (TelephonyManager.getDefault().getCallState() 253 == TelephonyManager.CALL_STATE_OFFHOOK) { 254 mLockPatternUtils.resumeCall(); 255 } else { 256 Intent intent = new Intent(ACTION_EMERGENCY_DIAL); 257 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 258 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 259 getContext().startActivity(intent); 260 } 261 } 262 263 public void pokeWakelock() { 264 getCallback().pokeWakelock(); 265 } 266 267 public void pokeWakelock(int millis) { 268 getCallback().pokeWakelock(millis); 269 } 270 271 public void keyguardDone(boolean authenticated) { 272 getCallback().keyguardDone(authenticated); 273 } 274 275 public void keyguardDoneDrawing() { 276 // irrelevant to keyguard screen, they shouldn't be calling this 277 } 278 279 public void reportFailedUnlockAttempt() { 280 mUpdateMonitor.reportFailedAttempt(); 281 final int failedAttempts = mUpdateMonitor.getFailedAttempts(); 282 if (DEBUG) Log.d(TAG, 283 "reportFailedPatternAttempt: #" + failedAttempts + 284 " (enableFallback=" + mEnableFallback + ")"); 285 final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() 286 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 287 if (usingLockPattern && mEnableFallback && failedAttempts == 288 (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 289 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { 290 showAlmostAtAccountLoginDialog(); 291 } else if (usingLockPattern && mEnableFallback 292 && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { 293 mLockPatternUtils.setPermanentlyLocked(true); 294 updateScreen(mMode); 295 } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) 296 == 0) { 297 showTimeoutDialog(); 298 } 299 mLockPatternUtils.reportFailedPasswordAttempt(); 300 } 301 302 public boolean doesFallbackUnlockScreenExist() { 303 return mEnableFallback; 304 } 305 306 public void reportSuccessfulUnlockAttempt() { 307 mLockPatternUtils.reportSuccessfulPasswordAttempt(); 308 } 309 }; 310 311 /** 312 * We'll get key events the current screen doesn't use. see 313 * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} 314 */ 315 setFocusableInTouchMode(true); 316 setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 317 318 // create both the lock and unlock screen so they are quickly available 319 // when the screen turns on 320 mLockScreen = createLockScreen(); 321 addView(mLockScreen); 322 final UnlockMode unlockMode = getUnlockMode(); 323 if (DEBUG) Log.d(TAG, 324 "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback=" 325 + mEnableFallback); 326 mUnlockScreen = createUnlockScreenFor(unlockMode); 327 mUnlockScreenMode = unlockMode; 328 329 maybeEnableFallback(context); 330 331 addView(mUnlockScreen); 332 updateScreen(mMode); 333 } 334 335 private class AccountAnalyzer implements AccountManagerCallback<Bundle> { 336 private final AccountManager mAccountManager; 337 private final Account[] mAccounts; 338 private int mAccountIndex; 339 340 private AccountAnalyzer(AccountManager accountManager) { 341 mAccountManager = accountManager; 342 mAccounts = accountManager.getAccountsByType("com.google"); 343 } 344 345 private void next() { 346 // if we are ready to enable the fallback or if we depleted the list of accounts 347 // then finish and get out 348 if (mEnableFallback || mAccountIndex >= mAccounts.length) { 349 if (mUnlockScreen == null) { 350 Log.w(TAG, "no unlock screen when trying to enable fallback"); 351 } else if (mUnlockScreen instanceof PatternUnlockScreen) { 352 ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); 353 } 354 return; 355 } 356 357 // lookup the confirmCredentials intent for the current account 358 mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null); 359 } 360 361 public void start() { 362 mEnableFallback = false; 363 mAccountIndex = 0; 364 next(); 365 } 366 367 public void run(AccountManagerFuture<Bundle> future) { 368 try { 369 Bundle result = future.getResult(); 370 if (result.getParcelable(AccountManager.KEY_INTENT) != null) { 371 mEnableFallback = true; 372 } 373 } catch (OperationCanceledException e) { 374 // just skip the account if we are unable to query it 375 } catch (IOException e) { 376 // just skip the account if we are unable to query it 377 } catch (AuthenticatorException e) { 378 // just skip the account if we are unable to query it 379 } finally { 380 mAccountIndex++; 381 next(); 382 } 383 } 384 } 385 386 private void maybeEnableFallback(Context context) { 387 // Ask the account manager if we have an account that can be used as a 388 // fallback in case the user forgets his pattern. 389 AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context)); 390 accountAnalyzer.start(); 391 } 392 393 394 // TODO: 395 // This overloaded method was added to workaround a race condition in the framework between 396 // notification for orientation changed, layout() and switching resources. This code attempts 397 // to avoid drawing the incorrect layout while things are in transition. The method can just 398 // be removed once the race condition is fixed. See bugs 2262578 and 2292713. 399 @Override 400 protected void dispatchDraw(Canvas canvas) { 401 if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime()); 402 super.dispatchDraw(canvas); 403 } 404 405 @Override 406 public void reset() { 407 mIsVerifyUnlockOnly = false; 408 mForgotPattern = false; 409 updateScreen(getInitialMode()); 410 } 411 412 @Override 413 public void onScreenTurnedOff() { 414 mScreenOn = false; 415 mForgotPattern = false; 416 if (mMode == Mode.LockScreen) { 417 ((KeyguardScreen) mLockScreen).onPause(); 418 } else { 419 ((KeyguardScreen) mUnlockScreen).onPause(); 420 } 421 } 422 423 @Override 424 public void onScreenTurnedOn() { 425 mScreenOn = true; 426 if (mMode == Mode.LockScreen) { 427 ((KeyguardScreen) mLockScreen).onResume(); 428 } else { 429 ((KeyguardScreen) mUnlockScreen).onResume(); 430 } 431 } 432 433 private void recreateLockScreen() { 434 if (mLockScreen.getVisibility() == View.VISIBLE) { 435 ((KeyguardScreen) mLockScreen).onPause(); 436 } 437 ((KeyguardScreen) mLockScreen).cleanUp(); 438 removeView(mLockScreen); 439 440 mLockScreen = createLockScreen(); 441 mLockScreen.setVisibility(View.INVISIBLE); 442 addView(mLockScreen); 443 } 444 445 private void recreateUnlockScreen() { 446 if (mUnlockScreen.getVisibility() == View.VISIBLE) { 447 ((KeyguardScreen) mUnlockScreen).onPause(); 448 } 449 ((KeyguardScreen) mUnlockScreen).cleanUp(); 450 removeView(mUnlockScreen); 451 452 final UnlockMode unlockMode = getUnlockMode(); 453 mUnlockScreen = createUnlockScreenFor(unlockMode); 454 mUnlockScreen.setVisibility(View.INVISIBLE); 455 mUnlockScreenMode = unlockMode; 456 addView(mUnlockScreen); 457 } 458 459 private void recreateScreens() { 460 recreateLockScreen(); 461 recreateUnlockScreen(); 462 updateScreen(mMode); 463 } 464 465 @Override 466 public void wakeWhenReadyTq(int keyCode) { 467 if (DEBUG) Log.d(TAG, "onWakeKey"); 468 if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) 469 && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) { 470 if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); 471 updateScreen(Mode.UnlockScreen); 472 getCallback().pokeWakelock(); 473 } else { 474 if (DEBUG) Log.d(TAG, "poking wake lock immediately"); 475 getCallback().pokeWakelock(); 476 } 477 } 478 479 @Override 480 public void verifyUnlock() { 481 if (!isSecure()) { 482 // non-secure keyguard screens are successfull by default 483 getCallback().keyguardDone(true); 484 } else if (mUnlockScreenMode != UnlockMode.Pattern) { 485 // can only verify unlock when in pattern mode 486 getCallback().keyguardDone(false); 487 } else { 488 // otherwise, go to the unlock screen, see if they can verify it 489 mIsVerifyUnlockOnly = true; 490 updateScreen(Mode.UnlockScreen); 491 } 492 } 493 494 @Override 495 public void cleanUp() { 496 ((KeyguardScreen) mLockScreen).onPause(); 497 ((KeyguardScreen) mLockScreen).cleanUp(); 498 ((KeyguardScreen) mUnlockScreen).onPause(); 499 ((KeyguardScreen) mUnlockScreen).cleanUp(); 500 } 501 502 private boolean isSecure() { 503 UnlockMode unlockMode = getUnlockMode(); 504 boolean secure = false; 505 switch (unlockMode) { 506 case Pattern: 507 secure = mLockPatternUtils.isLockPatternEnabled(); 508 break; 509 case SimPin: 510 secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED 511 || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; 512 break; 513 case Account: 514 secure = true; 515 break; 516 case Password: 517 secure = mLockPatternUtils.isLockPasswordEnabled(); 518 break; 519 default: 520 throw new IllegalStateException("unknown unlock mode " + unlockMode); 521 } 522 return secure; 523 } 524 525 private void updateScreen(final Mode mode) { 526 527 if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode 528 + " last mode=" + mMode, new RuntimeException()); 529 530 mMode = mode; 531 532 // Re-create the unlock screen if necessary. This is primarily required to properly handle 533 // SIM state changes. This typically happens when this method is called by reset() 534 if (mode == Mode.UnlockScreen && mCurrentUnlockMode != getUnlockMode()) { 535 recreateUnlockScreen(); 536 } 537 538 final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; 539 final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; 540 541 // do this before changing visibility so focus isn't requested before the input 542 // flag is set 543 mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); 544 545 if (DEBUG_CONFIGURATION) { 546 Log.v(TAG, "Gone=" + goneScreen); 547 Log.v(TAG, "Visible=" + visibleScreen); 548 } 549 550 if (mScreenOn) { 551 if (goneScreen.getVisibility() == View.VISIBLE) { 552 ((KeyguardScreen) goneScreen).onPause(); 553 } 554 if (visibleScreen.getVisibility() != View.VISIBLE) { 555 ((KeyguardScreen) visibleScreen).onResume(); 556 } 557 } 558 559 goneScreen.setVisibility(View.GONE); 560 visibleScreen.setVisibility(View.VISIBLE); 561 requestLayout(); 562 563 if (!visibleScreen.requestFocus()) { 564 throw new IllegalStateException("keyguard screen must be able to take " 565 + "focus when shown " + visibleScreen.getClass().getCanonicalName()); 566 } 567 } 568 569 View createLockScreen() { 570 return new LockScreen( 571 mContext, 572 mConfiguration, 573 mLockPatternUtils, 574 mUpdateMonitor, 575 mKeyguardScreenCallback); 576 } 577 578 View createUnlockScreenFor(UnlockMode unlockMode) { 579 View unlockView = null; 580 if (unlockMode == UnlockMode.Pattern) { 581 PatternUnlockScreen view = new PatternUnlockScreen( 582 mContext, 583 mConfiguration, 584 mLockPatternUtils, 585 mUpdateMonitor, 586 mKeyguardScreenCallback, 587 mUpdateMonitor.getFailedAttempts()); 588 if (DEBUG) Log.d(TAG, 589 "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); 590 view.setEnableFallback(mEnableFallback); 591 unlockView = view; 592 } else if (unlockMode == UnlockMode.SimPin) { 593 unlockView = new SimUnlockScreen( 594 mContext, 595 mConfiguration, 596 mUpdateMonitor, 597 mKeyguardScreenCallback, 598 mLockPatternUtils); 599 } else if (unlockMode == UnlockMode.Account) { 600 try { 601 unlockView = new AccountUnlockScreen( 602 mContext, 603 mConfiguration, 604 mUpdateMonitor, 605 mKeyguardScreenCallback, 606 mLockPatternUtils); 607 } catch (IllegalStateException e) { 608 Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" 609 + " (IAccountsService isn't available)"); 610 // TODO: Need a more general way to provide a 611 // platform-specific fallback UI here. 612 // For now, if we can't display the account login 613 // unlock UI, just bring back the regular "Pattern" unlock mode. 614 615 // (We do this by simply returning a regular UnlockScreen 616 // here. This means that the user will still see the 617 // regular pattern unlock UI, regardless of the value of 618 // mUnlockScreenMode or whether or not we're in the 619 // "permanently locked" state.) 620 unlockView = createUnlockScreenFor(UnlockMode.Pattern); 621 } 622 } else if (unlockMode == UnlockMode.Password) { 623 unlockView = new PasswordUnlockScreen( 624 mContext, 625 mConfiguration, 626 mLockPatternUtils, 627 mUpdateMonitor, 628 mKeyguardScreenCallback); 629 } else { 630 throw new IllegalArgumentException("unknown unlock mode " + unlockMode); 631 } 632 mCurrentUnlockMode = unlockMode; 633 return unlockView; 634 } 635 636 /** 637 * Given the current state of things, what should be the initial mode of 638 * the lock screen (lock or unlock). 639 */ 640 private Mode getInitialMode() { 641 final IccCard.State simState = mUpdateMonitor.getSimState(); 642 if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { 643 return Mode.LockScreen; 644 } else { 645 // Show LockScreen first for any screen other than Pattern unlock. 646 final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() 647 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 648 if (isSecure() && usingLockPattern) { 649 return Mode.UnlockScreen; 650 } else { 651 return Mode.LockScreen; 652 } 653 } 654 } 655 656 /** 657 * Given the current state of things, what should the unlock screen be? 658 */ 659 private UnlockMode getUnlockMode() { 660 final IccCard.State simState = mUpdateMonitor.getSimState(); 661 UnlockMode currentMode; 662 if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { 663 currentMode = UnlockMode.SimPin; 664 } else { 665 final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality(); 666 switch (mode) { 667 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 668 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 669 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 670 currentMode = UnlockMode.Password; 671 break; 672 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 673 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: 674 // "forgot pattern" button is only available in the pattern mode... 675 if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { 676 currentMode = UnlockMode.Account; 677 } else { 678 currentMode = UnlockMode.Pattern; 679 } 680 break; 681 default: 682 throw new IllegalStateException("Unknown unlock mode:" + mode); 683 } 684 } 685 return currentMode; 686 } 687 688 private void showTimeoutDialog() { 689 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 690 String message = mContext.getString( 691 R.string.lockscreen_too_many_failed_attempts_dialog_message, 692 mUpdateMonitor.getFailedAttempts(), 693 timeoutInSeconds); 694 final AlertDialog dialog = new AlertDialog.Builder(mContext) 695 .setTitle(null) 696 .setMessage(message) 697 .setNeutralButton(R.string.ok, null) 698 .create(); 699 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 700 if (!mContext.getResources().getBoolean( 701 com.android.internal.R.bool.config_sf_slowBlur)) { 702 dialog.getWindow().setFlags( 703 WindowManager.LayoutParams.FLAG_BLUR_BEHIND, 704 WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 705 } 706 dialog.show(); 707 } 708 709 private void showAlmostAtAccountLoginDialog() { 710 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 711 String message = mContext.getString( 712 R.string.lockscreen_failed_attempts_almost_glogin, 713 LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 714 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, 715 LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, 716 timeoutInSeconds); 717 final AlertDialog dialog = new AlertDialog.Builder(mContext) 718 .setTitle(null) 719 .setMessage(message) 720 .setNeutralButton(R.string.ok, null) 721 .create(); 722 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 723 if (!mContext.getResources().getBoolean( 724 com.android.internal.R.bool.config_sf_slowBlur)) { 725 dialog.getWindow().setFlags( 726 WindowManager.LayoutParams.FLAG_BLUR_BEHIND, 727 WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 728 } 729 dialog.show(); 730 } 731 732 /** 733 * Used to put wallpaper on the background of the lock screen. Centers it 734 * Horizontally and pins the bottom (assuming that the lock screen is aligned 735 * with the bottom, so the wallpaper should extend above the top into the 736 * status bar). 737 */ 738 static private class FastBitmapDrawable extends Drawable { 739 private Bitmap mBitmap; 740 private int mOpacity; 741 742 private FastBitmapDrawable(Bitmap bitmap) { 743 mBitmap = bitmap; 744 mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 745 } 746 747 @Override 748 public void draw(Canvas canvas) { 749 canvas.drawBitmap( 750 mBitmap, 751 (getBounds().width() - mBitmap.getWidth()) / 2, 752 (getBounds().height() - mBitmap.getHeight()), 753 null); 754 } 755 756 @Override 757 public int getOpacity() { 758 return mOpacity; 759 } 760 761 @Override 762 public void setAlpha(int alpha) { 763 } 764 765 @Override 766 public void setColorFilter(ColorFilter cf) { 767 } 768 769 @Override 770 public int getIntrinsicWidth() { 771 return mBitmap.getWidth(); 772 } 773 774 @Override 775 public int getIntrinsicHeight() { 776 return mBitmap.getHeight(); 777 } 778 779 @Override 780 public int getMinimumWidth() { 781 return mBitmap.getWidth(); 782 } 783 784 @Override 785 public int getMinimumHeight() { 786 return mBitmap.getHeight(); 787 } 788 } 789 } 790 791