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