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 */ stuckOnLockScreenBecauseSimMissing()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 */ LockPatternKeyguardView( Context context, KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils, KeyguardWindowController controller)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 AccountAnalyzer(AccountManager accountManager)340 private AccountAnalyzer(AccountManager accountManager) { 341 mAccountManager = accountManager; 342 mAccounts = accountManager.getAccountsByType("com.google"); 343 } 344 next()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 start()361 public void start() { 362 mEnableFallback = false; 363 mAccountIndex = 0; 364 next(); 365 } 366 run(AccountManagerFuture<Bundle> future)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 maybeEnableFallback(Context context)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 dispatchDraw(Canvas canvas)400 protected void dispatchDraw(Canvas canvas) { 401 if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime()); 402 super.dispatchDraw(canvas); 403 } 404 405 @Override reset()406 public void reset() { 407 mIsVerifyUnlockOnly = false; 408 mForgotPattern = false; 409 updateScreen(getInitialMode()); 410 } 411 412 @Override onScreenTurnedOff()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 onScreenTurnedOn()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 recreateLockScreen()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 recreateUnlockScreen()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 recreateScreens()459 private void recreateScreens() { 460 recreateLockScreen(); 461 recreateUnlockScreen(); 462 updateScreen(mMode); 463 } 464 465 @Override wakeWhenReadyTq(int keyCode)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 verifyUnlock()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 cleanUp()495 public void cleanUp() { 496 ((KeyguardScreen) mLockScreen).onPause(); 497 ((KeyguardScreen) mLockScreen).cleanUp(); 498 this.removeView(mLockScreen); 499 ((KeyguardScreen) mUnlockScreen).onPause(); 500 ((KeyguardScreen) mUnlockScreen).cleanUp(); 501 this.removeView(mUnlockScreen); 502 } 503 isSecure()504 private boolean isSecure() { 505 UnlockMode unlockMode = getUnlockMode(); 506 boolean secure = false; 507 switch (unlockMode) { 508 case Pattern: 509 secure = mLockPatternUtils.isLockPatternEnabled(); 510 break; 511 case SimPin: 512 secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED 513 || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; 514 break; 515 case Account: 516 secure = true; 517 break; 518 case Password: 519 secure = mLockPatternUtils.isLockPasswordEnabled(); 520 break; 521 default: 522 throw new IllegalStateException("unknown unlock mode " + unlockMode); 523 } 524 return secure; 525 } 526 updateScreen(final Mode mode)527 private void updateScreen(final Mode mode) { 528 529 if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode 530 + " last mode=" + mMode, new RuntimeException()); 531 532 mMode = mode; 533 534 // Re-create the unlock screen if necessary. This is primarily required to properly handle 535 // SIM state changes. This typically happens when this method is called by reset() 536 if (mode == Mode.UnlockScreen && mCurrentUnlockMode != getUnlockMode()) { 537 recreateUnlockScreen(); 538 } 539 540 final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; 541 final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; 542 543 // do this before changing visibility so focus isn't requested before the input 544 // flag is set 545 mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); 546 547 if (DEBUG_CONFIGURATION) { 548 Log.v(TAG, "Gone=" + goneScreen); 549 Log.v(TAG, "Visible=" + visibleScreen); 550 } 551 552 if (mScreenOn) { 553 if (goneScreen.getVisibility() == View.VISIBLE) { 554 ((KeyguardScreen) goneScreen).onPause(); 555 } 556 if (visibleScreen.getVisibility() != View.VISIBLE) { 557 ((KeyguardScreen) visibleScreen).onResume(); 558 } 559 } 560 561 goneScreen.setVisibility(View.GONE); 562 visibleScreen.setVisibility(View.VISIBLE); 563 requestLayout(); 564 565 if (!visibleScreen.requestFocus()) { 566 throw new IllegalStateException("keyguard screen must be able to take " 567 + "focus when shown " + visibleScreen.getClass().getCanonicalName()); 568 } 569 } 570 createLockScreen()571 View createLockScreen() { 572 return new LockScreen( 573 mContext, 574 mConfiguration, 575 mLockPatternUtils, 576 mUpdateMonitor, 577 mKeyguardScreenCallback); 578 } 579 createUnlockScreenFor(UnlockMode unlockMode)580 View createUnlockScreenFor(UnlockMode unlockMode) { 581 View unlockView = null; 582 if (unlockMode == UnlockMode.Pattern) { 583 PatternUnlockScreen view = new PatternUnlockScreen( 584 mContext, 585 mConfiguration, 586 mLockPatternUtils, 587 mUpdateMonitor, 588 mKeyguardScreenCallback, 589 mUpdateMonitor.getFailedAttempts()); 590 if (DEBUG) Log.d(TAG, 591 "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); 592 view.setEnableFallback(mEnableFallback); 593 unlockView = view; 594 } else if (unlockMode == UnlockMode.SimPin) { 595 unlockView = new SimUnlockScreen( 596 mContext, 597 mConfiguration, 598 mUpdateMonitor, 599 mKeyguardScreenCallback, 600 mLockPatternUtils); 601 } else if (unlockMode == UnlockMode.Account) { 602 try { 603 unlockView = new AccountUnlockScreen( 604 mContext, 605 mConfiguration, 606 mUpdateMonitor, 607 mKeyguardScreenCallback, 608 mLockPatternUtils); 609 } catch (IllegalStateException e) { 610 Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" 611 + " (IAccountsService isn't available)"); 612 // TODO: Need a more general way to provide a 613 // platform-specific fallback UI here. 614 // For now, if we can't display the account login 615 // unlock UI, just bring back the regular "Pattern" unlock mode. 616 617 // (We do this by simply returning a regular UnlockScreen 618 // here. This means that the user will still see the 619 // regular pattern unlock UI, regardless of the value of 620 // mUnlockScreenMode or whether or not we're in the 621 // "permanently locked" state.) 622 unlockView = createUnlockScreenFor(UnlockMode.Pattern); 623 } 624 } else if (unlockMode == UnlockMode.Password) { 625 unlockView = new PasswordUnlockScreen( 626 mContext, 627 mConfiguration, 628 mLockPatternUtils, 629 mUpdateMonitor, 630 mKeyguardScreenCallback); 631 } else { 632 throw new IllegalArgumentException("unknown unlock mode " + unlockMode); 633 } 634 mCurrentUnlockMode = unlockMode; 635 return unlockView; 636 } 637 638 /** 639 * Given the current state of things, what should be the initial mode of 640 * the lock screen (lock or unlock). 641 */ getInitialMode()642 private Mode getInitialMode() { 643 final IccCard.State simState = mUpdateMonitor.getSimState(); 644 if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) { 645 return Mode.LockScreen; 646 } else { 647 // Show LockScreen first for any screen other than Pattern unlock. 648 final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() 649 == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 650 if (isSecure() && usingLockPattern) { 651 return Mode.UnlockScreen; 652 } else { 653 return Mode.LockScreen; 654 } 655 } 656 } 657 658 /** 659 * Given the current state of things, what should the unlock screen be? 660 */ getUnlockMode()661 private UnlockMode getUnlockMode() { 662 final IccCard.State simState = mUpdateMonitor.getSimState(); 663 UnlockMode currentMode; 664 if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { 665 currentMode = UnlockMode.SimPin; 666 } else { 667 final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality(); 668 switch (mode) { 669 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 670 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 671 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 672 currentMode = UnlockMode.Password; 673 break; 674 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 675 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: 676 // "forgot pattern" button is only available in the pattern mode... 677 if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { 678 currentMode = UnlockMode.Account; 679 } else { 680 currentMode = UnlockMode.Pattern; 681 } 682 break; 683 default: 684 throw new IllegalStateException("Unknown unlock mode:" + mode); 685 } 686 } 687 return currentMode; 688 } 689 showTimeoutDialog()690 private void showTimeoutDialog() { 691 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 692 String message = mContext.getString( 693 R.string.lockscreen_too_many_failed_attempts_dialog_message, 694 mUpdateMonitor.getFailedAttempts(), 695 timeoutInSeconds); 696 final AlertDialog dialog = new AlertDialog.Builder(mContext) 697 .setTitle(null) 698 .setMessage(message) 699 .setNeutralButton(R.string.ok, null) 700 .create(); 701 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 702 if (!mContext.getResources().getBoolean( 703 com.android.internal.R.bool.config_sf_slowBlur)) { 704 dialog.getWindow().setFlags( 705 WindowManager.LayoutParams.FLAG_BLUR_BEHIND, 706 WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 707 } 708 dialog.show(); 709 } 710 showAlmostAtAccountLoginDialog()711 private void showAlmostAtAccountLoginDialog() { 712 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 713 String message = mContext.getString( 714 R.string.lockscreen_failed_attempts_almost_glogin, 715 LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 716 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, 717 LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, 718 timeoutInSeconds); 719 final AlertDialog dialog = new AlertDialog.Builder(mContext) 720 .setTitle(null) 721 .setMessage(message) 722 .setNeutralButton(R.string.ok, null) 723 .create(); 724 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 725 if (!mContext.getResources().getBoolean( 726 com.android.internal.R.bool.config_sf_slowBlur)) { 727 dialog.getWindow().setFlags( 728 WindowManager.LayoutParams.FLAG_BLUR_BEHIND, 729 WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 730 } 731 dialog.show(); 732 } 733 734 /** 735 * Used to put wallpaper on the background of the lock screen. Centers it 736 * Horizontally and pins the bottom (assuming that the lock screen is aligned 737 * with the bottom, so the wallpaper should extend above the top into the 738 * status bar). 739 */ 740 static private class FastBitmapDrawable extends Drawable { 741 private Bitmap mBitmap; 742 private int mOpacity; 743 FastBitmapDrawable(Bitmap bitmap)744 private FastBitmapDrawable(Bitmap bitmap) { 745 mBitmap = bitmap; 746 mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 747 } 748 749 @Override draw(Canvas canvas)750 public void draw(Canvas canvas) { 751 canvas.drawBitmap( 752 mBitmap, 753 (getBounds().width() - mBitmap.getWidth()) / 2, 754 (getBounds().height() - mBitmap.getHeight()), 755 null); 756 } 757 758 @Override getOpacity()759 public int getOpacity() { 760 return mOpacity; 761 } 762 763 @Override setAlpha(int alpha)764 public void setAlpha(int alpha) { 765 } 766 767 @Override setColorFilter(ColorFilter cf)768 public void setColorFilter(ColorFilter cf) { 769 } 770 771 @Override getIntrinsicWidth()772 public int getIntrinsicWidth() { 773 return mBitmap.getWidth(); 774 } 775 776 @Override getIntrinsicHeight()777 public int getIntrinsicHeight() { 778 return mBitmap.getHeight(); 779 } 780 781 @Override getMinimumWidth()782 public int getMinimumWidth() { 783 return mBitmap.getWidth(); 784 } 785 786 @Override getMinimumHeight()787 public int getMinimumHeight() { 788 return mBitmap.getHeight(); 789 } 790 } 791 } 792 793