LockPatternKeyguardView.java revision f13313a073ad3f3c4e91baa4adbfdec66395065e
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 { 425 boolean showTimeout = 426 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0; 427 if (usingPattern && mEnableFallback) { 428 if (failedAttempts == failedAttemptWarning) { 429 showAlmostAtAccountLoginDialog(); 430 showTimeout = false; // don't show both dialogs 431 } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { 432 mLockPatternUtils.setPermanentlyLocked(true); 433 updateScreen(mMode, false); 434 // don't show timeout dialog because we show account unlock screen next 435 showTimeout = false; 436 } 437 } 438 if (showTimeout) { 439 showTimeoutDialog(); 440 } 441 } 442 mLockPatternUtils.reportFailedPasswordAttempt(); 443 } 444 445 public boolean doesFallbackUnlockScreenExist() { 446 return mEnableFallback; 447 } 448 449 public void reportSuccessfulUnlockAttempt() { 450 mFailedFaceUnlockAttempts = 0; 451 mLockPatternUtils.reportSuccessfulPasswordAttempt(); 452 } 453 }; 454 455 /** 456 * We'll get key events the current screen doesn't use. see 457 * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} 458 */ 459 setFocusableInTouchMode(true); 460 setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 461 462 updateScreen(getInitialMode(), false); 463 maybeEnableFallback(context); 464 } 465 466 private class AccountAnalyzer implements AccountManagerCallback<Bundle> { 467 private final AccountManager mAccountManager; 468 private final Account[] mAccounts; 469 private int mAccountIndex; 470 471 private AccountAnalyzer(AccountManager accountManager) { 472 mAccountManager = accountManager; 473 mAccounts = accountManager.getAccountsByType("com.google"); 474 } 475 476 private void next() { 477 // if we are ready to enable the fallback or if we depleted the list of accounts 478 // then finish and get out 479 if (mEnableFallback || mAccountIndex >= mAccounts.length) { 480 if (mUnlockScreen == null) { 481 if (DEBUG) Log.w(TAG, "no unlock screen when trying to enable fallback"); 482 } else if (mUnlockScreen instanceof PatternUnlockScreen) { 483 ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); 484 } 485 return; 486 } 487 488 // lookup the confirmCredentials intent for the current account 489 mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null); 490 } 491 492 public void start() { 493 mEnableFallback = false; 494 mAccountIndex = 0; 495 next(); 496 } 497 498 public void run(AccountManagerFuture<Bundle> future) { 499 try { 500 Bundle result = future.getResult(); 501 if (result.getParcelable(AccountManager.KEY_INTENT) != null) { 502 mEnableFallback = true; 503 } 504 } catch (OperationCanceledException e) { 505 // just skip the account if we are unable to query it 506 } catch (IOException e) { 507 // just skip the account if we are unable to query it 508 } catch (AuthenticatorException e) { 509 // just skip the account if we are unable to query it 510 } finally { 511 mAccountIndex++; 512 next(); 513 } 514 } 515 } 516 517 private void maybeEnableFallback(Context context) { 518 // Ask the account manager if we have an account that can be used as a 519 // fallback in case the user forgets his pattern. 520 AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context)); 521 accountAnalyzer.start(); 522 } 523 524 525 // TODO: 526 // This overloaded method was added to workaround a race condition in the framework between 527 // notification for orientation changed, layout() and switching resources. This code attempts 528 // to avoid drawing the incorrect layout while things are in transition. The method can just 529 // be removed once the race condition is fixed. See bugs 2262578 and 2292713. 530 @Override 531 protected void dispatchDraw(Canvas canvas) { 532 if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime()); 533 super.dispatchDraw(canvas); 534 } 535 536 @Override 537 public void reset() { 538 mIsVerifyUnlockOnly = false; 539 mForgotPattern = false; 540 post(mRecreateRunnable); 541 } 542 543 @Override 544 public void onScreenTurnedOff() { 545 if (DEBUG) Log.d(TAG, "screen off"); 546 mScreenOn = false; 547 mForgotPattern = false; 548 mHasOverlay = mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE; 549 if (mMode == Mode.LockScreen) { 550 ((KeyguardScreen) mLockScreen).onPause(); 551 } else { 552 ((KeyguardScreen) mUnlockScreen).onPause(); 553 } 554 555 saveWidgetState(); 556 557 // When screen is turned off, need to unbind from FaceLock service if using FaceLock 558 stopAndUnbindFromFaceLock(); 559 } 560 561 /** When screen is turned on and focused, need to bind to FaceLock service if we are using 562 * FaceLock, but only if we're not dealing with a call 563 */ 564 private void activateFaceLockIfAble() { 565 final boolean tooManyFaceUnlockTries = 566 (mFailedFaceUnlockAttempts >= FAILED_FACE_UNLOCK_ATTEMPTS_BEFORE_BACKUP); 567 final int failedBackupAttempts = mUpdateMonitor.getFailedAttempts(); 568 final boolean backupIsTimedOut = 569 (failedBackupAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT); 570 if (tooManyFaceUnlockTries) Log.i(TAG, "tooManyFaceUnlockTries: " + tooManyFaceUnlockTries); 571 if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE 572 && !mHasOverlay 573 && !tooManyFaceUnlockTries 574 && !backupIsTimedOut) { 575 bindToFaceLock(); 576 // Show FaceLock area, but only for a little bit so lockpattern will become visible if 577 // FaceLock fails to start or crashes 578 if (mLockPatternUtils.usingBiometricWeak() && 579 mLockPatternUtils.isBiometricWeakInstalled()) { 580 showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_SERVICE_TIMEOUT); 581 } 582 } else { 583 hideFaceLockArea(); 584 } 585 } 586 587 @Override 588 public void onScreenTurnedOn() { 589 if (DEBUG) Log.d(TAG, "screen on"); 590 boolean runFaceLock = false; 591 //Make sure to start facelock iff the screen is both on and focused 592 synchronized(mFaceLockStartupLock) { 593 mScreenOn = true; 594 runFaceLock = mWindowFocused; 595 } 596 597 show(); 598 599 restoreWidgetState(); 600 601 if (runFaceLock) activateFaceLockIfAble(); 602 } 603 604 private void saveWidgetState() { 605 if (mTransportControlView != null) { 606 if (DEBUG) Log.v(TAG, "Saving widget state"); 607 mSavedState = mTransportControlView.onSaveInstanceState(); 608 } 609 } 610 611 private void restoreWidgetState() { 612 if (mTransportControlView != null) { 613 if (DEBUG) Log.v(TAG, "Restoring widget state"); 614 if (mSavedState != null) { 615 mTransportControlView.onRestoreInstanceState(mSavedState); 616 } 617 } 618 } 619 620 /** Unbind from facelock if something covers this window (such as an alarm) 621 * bind to facelock if the lockscreen window just came into focus, and the screen is on 622 */ 623 @Override 624 public void onWindowFocusChanged (boolean hasWindowFocus) { 625 if (DEBUG) Log.d(TAG, hasWindowFocus ? "focused" : "unfocused"); 626 boolean runFaceLock = false; 627 //Make sure to start facelock iff the screen is both on and focused 628 synchronized(mFaceLockStartupLock) { 629 if(mScreenOn && !mWindowFocused) runFaceLock = hasWindowFocus; 630 mWindowFocused = hasWindowFocus; 631 } 632 if(!hasWindowFocus) { 633 mHasOverlay = true; 634 stopAndUnbindFromFaceLock(); 635 hideFaceLockArea(); 636 } else if (runFaceLock) { 637 activateFaceLockIfAble(); 638 } 639 } 640 641 @Override 642 public void show() { 643 if (mMode == Mode.LockScreen) { 644 ((KeyguardScreen) mLockScreen).onResume(); 645 } else { 646 ((KeyguardScreen) mUnlockScreen).onResume(); 647 } 648 649 if (mLockPatternUtils.usingBiometricWeak() && 650 mLockPatternUtils.isBiometricWeakInstalled() && !mHasOverlay) { 651 // Note that show() gets called before the screen turns off to set it up for next time 652 // it is turned on. We don't want to set a timeout on the FaceLock area here because it 653 // may be gone by the time the screen is turned on again. We set the timout when the 654 // screen turns on instead. 655 showFaceLockArea(); 656 } else { 657 hideFaceLockArea(); 658 } 659 } 660 661 private void recreateLockScreen() { 662 if (mLockScreen != null) { 663 ((KeyguardScreen) mLockScreen).onPause(); 664 ((KeyguardScreen) mLockScreen).cleanUp(); 665 removeView(mLockScreen); 666 } 667 668 mLockScreen = createLockScreen(); 669 mLockScreen.setVisibility(View.INVISIBLE); 670 addView(mLockScreen); 671 } 672 673 private void recreateUnlockScreen(UnlockMode unlockMode) { 674 if (mUnlockScreen != null) { 675 ((KeyguardScreen) mUnlockScreen).onPause(); 676 ((KeyguardScreen) mUnlockScreen).cleanUp(); 677 removeView(mUnlockScreen); 678 } 679 680 mUnlockScreen = createUnlockScreenFor(unlockMode); 681 mUnlockScreen.setVisibility(View.INVISIBLE); 682 addView(mUnlockScreen); 683 } 684 685 @Override 686 protected void onDetachedFromWindow() { 687 removeCallbacks(mRecreateRunnable); 688 689 // When view is hidden, need to unbind from FaceLock service if we are using FaceLock 690 // e.g., when device becomes unlocked 691 stopAndUnbindFromFaceLock(); 692 693 super.onDetachedFromWindow(); 694 } 695 696 protected void onConfigurationChanged(Configuration newConfig) { 697 Resources resources = getResources(); 698 mShowLockBeforeUnlock = resources.getBoolean(R.bool.config_enableLockBeforeUnlockScreen); 699 mConfiguration = newConfig; 700 if (DEBUG_CONFIGURATION) Log.v(TAG, "**** re-creating lock screen since config changed"); 701 saveWidgetState(); 702 removeCallbacks(mRecreateRunnable); 703 post(mRecreateRunnable); 704 } 705 706 //Ignore these events; they are implemented only because they come from the same interface 707 @Override 708 public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) 709 {} 710 @Override 711 public void onTimeChanged() {} 712 @Override 713 public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {} 714 @Override 715 public void onRingerModeChanged(int state) {} 716 717 @Override 718 public void onClockVisibilityChanged() { 719 int visFlags = getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK; 720 setSystemUiVisibility(visFlags 721 | (mUpdateMonitor.isClockVisible() ? View.STATUS_BAR_DISABLE_CLOCK : 0)); 722 } 723 724 @Override 725 public void onDeviceProvisioned() {} 726 727 //We need to stop faceunlock when a phonecall comes in 728 @Override 729 public void onPhoneStateChanged(int phoneState) { 730 if (DEBUG) Log.d(TAG, "phone state: " + phoneState); 731 if(phoneState == TelephonyManager.CALL_STATE_RINGING) { 732 mHasOverlay = true; 733 stopAndUnbindFromFaceLock(); 734 hideFaceLockArea(); 735 } 736 } 737 738 @Override 739 protected boolean dispatchHoverEvent(MotionEvent event) { 740 // Do not let the screen to get locked while the user is disabled and touch 741 // exploring. A blind user will need significantly more time to find and 742 // interact with the lock screen views. 743 AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext); 744 if (accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled()) { 745 getCallback().pokeWakelock(); 746 } 747 return super.dispatchHoverEvent(event); 748 } 749 750 @Override 751 public void wakeWhenReadyTq(int keyCode) { 752 if (DEBUG) Log.d(TAG, "onWakeKey"); 753 if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) 754 && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) { 755 if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); 756 updateScreen(Mode.UnlockScreen, false); 757 getCallback().pokeWakelock(); 758 } else { 759 if (DEBUG) Log.d(TAG, "poking wake lock immediately"); 760 getCallback().pokeWakelock(); 761 } 762 } 763 764 @Override 765 public void verifyUnlock() { 766 if (!isSecure()) { 767 // non-secure keyguard screens are successfull by default 768 getCallback().keyguardDone(true); 769 } else if (mUnlockScreenMode != UnlockMode.Pattern 770 && mUnlockScreenMode != UnlockMode.Password) { 771 // can only verify unlock when in pattern/password mode 772 getCallback().keyguardDone(false); 773 } else { 774 // otherwise, go to the unlock screen, see if they can verify it 775 mIsVerifyUnlockOnly = true; 776 updateScreen(Mode.UnlockScreen, false); 777 } 778 } 779 780 @Override 781 public void cleanUp() { 782 if (mLockScreen != null) { 783 ((KeyguardScreen) mLockScreen).onPause(); 784 ((KeyguardScreen) mLockScreen).cleanUp(); 785 this.removeView(mLockScreen); 786 mLockScreen = null; 787 } 788 if (mUnlockScreen != null) { 789 ((KeyguardScreen) mUnlockScreen).onPause(); 790 ((KeyguardScreen) mUnlockScreen).cleanUp(); 791 this.removeView(mUnlockScreen); 792 mUnlockScreen = null; 793 } 794 mUpdateMonitor.removeCallback(this); 795 if (mFaceLockService != null) { 796 try { 797 mFaceLockService.unregisterCallback(mFaceLockCallback); 798 } catch (RemoteException e) { 799 // Not much we can do 800 } 801 stopFaceLock(); 802 mFaceLockService = null; 803 } 804 } 805 806 private boolean isSecure() { 807 UnlockMode unlockMode = getUnlockMode(); 808 boolean secure = false; 809 switch (unlockMode) { 810 case Pattern: 811 secure = mLockPatternUtils.isLockPatternEnabled(); 812 break; 813 case SimPin: 814 secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED; 815 break; 816 case SimPuk: 817 secure = mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; 818 break; 819 case Account: 820 secure = true; 821 break; 822 case Password: 823 secure = mLockPatternUtils.isLockPasswordEnabled(); 824 break; 825 default: 826 throw new IllegalStateException("unknown unlock mode " + unlockMode); 827 } 828 return secure; 829 } 830 831 private void updateScreen(Mode mode, boolean force) { 832 833 if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode 834 + " last mode=" + mMode + ", force = " + force, new RuntimeException()); 835 836 mMode = mode; 837 838 // Re-create the lock screen if necessary 839 if (mode == Mode.LockScreen || mShowLockBeforeUnlock) { 840 if (force || mLockScreen == null) { 841 recreateLockScreen(); 842 } 843 } 844 845 // Re-create the unlock screen if necessary. This is primarily required to properly handle 846 // SIM state changes. This typically happens when this method is called by reset() 847 if (mode == Mode.UnlockScreen) { 848 final UnlockMode unlockMode = getUnlockMode(); 849 if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { 850 recreateUnlockScreen(unlockMode); 851 } 852 } 853 854 // visibleScreen should never be null 855 final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; 856 final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; 857 858 // do this before changing visibility so focus isn't requested before the input 859 // flag is set 860 mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); 861 862 if (DEBUG_CONFIGURATION) { 863 Log.v(TAG, "Gone=" + goneScreen); 864 Log.v(TAG, "Visible=" + visibleScreen); 865 } 866 867 if (mScreenOn) { 868 if (goneScreen != null && goneScreen.getVisibility() == View.VISIBLE) { 869 ((KeyguardScreen) goneScreen).onPause(); 870 } 871 if (visibleScreen.getVisibility() != View.VISIBLE) { 872 ((KeyguardScreen) visibleScreen).onResume(); 873 } 874 } 875 876 if (goneScreen != null) { 877 goneScreen.setVisibility(View.GONE); 878 } 879 visibleScreen.setVisibility(View.VISIBLE); 880 requestLayout(); 881 882 if (!visibleScreen.requestFocus()) { 883 throw new IllegalStateException("keyguard screen must be able to take " 884 + "focus when shown " + visibleScreen.getClass().getCanonicalName()); 885 } 886 } 887 888 View createLockScreen() { 889 View lockView = new LockScreen( 890 mContext, 891 mConfiguration, 892 mLockPatternUtils, 893 mUpdateMonitor, 894 mKeyguardScreenCallback); 895 initializeTransportControlView(lockView); 896 return lockView; 897 } 898 899 View createUnlockScreenFor(UnlockMode unlockMode) { 900 View unlockView = null; 901 902 if (DEBUG) Log.d(TAG, 903 "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); 904 905 if (unlockMode == UnlockMode.Pattern) { 906 PatternUnlockScreen view = new PatternUnlockScreen( 907 mContext, 908 mConfiguration, 909 mLockPatternUtils, 910 mUpdateMonitor, 911 mKeyguardScreenCallback, 912 mUpdateMonitor.getFailedAttempts()); 913 view.setEnableFallback(mEnableFallback); 914 unlockView = view; 915 } else if (unlockMode == UnlockMode.SimPuk) { 916 unlockView = new SimPukUnlockScreen( 917 mContext, 918 mConfiguration, 919 mUpdateMonitor, 920 mKeyguardScreenCallback, 921 mLockPatternUtils); 922 } else if (unlockMode == UnlockMode.SimPin) { 923 unlockView = new SimUnlockScreen( 924 mContext, 925 mConfiguration, 926 mUpdateMonitor, 927 mKeyguardScreenCallback, 928 mLockPatternUtils); 929 } else if (unlockMode == UnlockMode.Account) { 930 try { 931 unlockView = new AccountUnlockScreen( 932 mContext, 933 mConfiguration, 934 mUpdateMonitor, 935 mKeyguardScreenCallback, 936 mLockPatternUtils); 937 } catch (IllegalStateException e) { 938 Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" 939 + " (IAccountsService isn't available)"); 940 // TODO: Need a more general way to provide a 941 // platform-specific fallback UI here. 942 // For now, if we can't display the account login 943 // unlock UI, just bring back the regular "Pattern" unlock mode. 944 945 // (We do this by simply returning a regular UnlockScreen 946 // here. This means that the user will still see the 947 // regular pattern unlock UI, regardless of the value of 948 // mUnlockScreenMode or whether or not we're in the 949 // "permanently locked" state.) 950 return createUnlockScreenFor(UnlockMode.Pattern); 951 } 952 } else if (unlockMode == UnlockMode.Password) { 953 unlockView = new PasswordUnlockScreen( 954 mContext, 955 mConfiguration, 956 mLockPatternUtils, 957 mUpdateMonitor, 958 mKeyguardScreenCallback); 959 } else { 960 throw new IllegalArgumentException("unknown unlock mode " + unlockMode); 961 } 962 initializeTransportControlView(unlockView); 963 initializeFaceLockAreaView(unlockView); // Only shows view if FaceLock is enabled 964 965 mUnlockScreenMode = unlockMode; 966 return unlockView; 967 } 968 969 private void initializeTransportControlView(View view) { 970 mTransportControlView = (TransportControlView) view.findViewById(R.id.transport); 971 if (mTransportControlView == null) { 972 if (DEBUG) Log.w(TAG, "Couldn't find transport control widget"); 973 } else { 974 mUpdateMonitor.reportClockVisible(true); 975 mTransportControlView.setVisibility(View.GONE); // hide until it requests being shown. 976 mTransportControlView.setCallback(mWidgetCallback); 977 } 978 } 979 980 /** 981 * Given the current state of things, what should be the initial mode of 982 * the lock screen (lock or unlock). 983 */ 984 private Mode getInitialMode() { 985 final IccCard.State simState = mUpdateMonitor.getSimState(); 986 if (stuckOnLockScreenBecauseSimMissing() || 987 (simState == IccCard.State.PUK_REQUIRED && 988 !mLockPatternUtils.isPukUnlockScreenEnable())) { 989 return Mode.LockScreen; 990 } else { 991 if (!isSecure() || mShowLockBeforeUnlock) { 992 return Mode.LockScreen; 993 } else { 994 return Mode.UnlockScreen; 995 } 996 } 997 } 998 999 /** 1000 * Given the current state of things, what should the unlock screen be? 1001 */ 1002 private UnlockMode getUnlockMode() { 1003 final IccCard.State simState = mUpdateMonitor.getSimState(); 1004 UnlockMode currentMode; 1005 if (simState == IccCard.State.PIN_REQUIRED) { 1006 currentMode = UnlockMode.SimPin; 1007 } else if (simState == IccCard.State.PUK_REQUIRED) { 1008 currentMode = UnlockMode.SimPuk; 1009 } else { 1010 final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality(); 1011 switch (mode) { 1012 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 1013 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 1014 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 1015 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 1016 currentMode = UnlockMode.Password; 1017 break; 1018 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 1019 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: 1020 // "forgot pattern" button is only available in the pattern mode... 1021 if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { 1022 currentMode = UnlockMode.Account; 1023 } else { 1024 currentMode = UnlockMode.Pattern; 1025 } 1026 break; 1027 default: 1028 throw new IllegalStateException("Unknown unlock mode:" + mode); 1029 } 1030 } 1031 return currentMode; 1032 } 1033 1034 private void showDialog(String title, String message) { 1035 final AlertDialog dialog = new AlertDialog.Builder(mContext) 1036 .setTitle(title) 1037 .setMessage(message) 1038 .setNeutralButton(R.string.ok, null) 1039 .create(); 1040 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 1041 dialog.show(); 1042 } 1043 1044 private void showTimeoutDialog() { 1045 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 1046 int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message; 1047 if (getUnlockMode() == UnlockMode.Password) { 1048 if(mLockPatternUtils.getKeyguardStoredPasswordQuality() == 1049 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { 1050 messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message; 1051 } else { 1052 messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message; 1053 } 1054 } 1055 String message = mContext.getString(messageId, mUpdateMonitor.getFailedAttempts(), 1056 timeoutInSeconds); 1057 1058 showDialog(null, message); 1059 } 1060 1061 private void showAlmostAtAccountLoginDialog() { 1062 final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 1063 final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 1064 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 1065 String message = mContext.getString(R.string.lockscreen_failed_attempts_almost_glogin, 1066 count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); 1067 showDialog(null, message); 1068 } 1069 1070 private void showAlmostAtWipeDialog(int attempts, int remaining) { 1071 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 1072 String message = mContext.getString( 1073 R.string.lockscreen_failed_attempts_almost_at_wipe, attempts, remaining); 1074 showDialog(null, message); 1075 } 1076 1077 private void showWipeDialog(int attempts) { 1078 String message = mContext.getString( 1079 R.string.lockscreen_failed_attempts_now_wiping, attempts); 1080 showDialog(null, message); 1081 } 1082 1083 /** 1084 * Used to put wallpaper on the background of the lock screen. Centers it 1085 * Horizontally and pins the bottom (assuming that the lock screen is aligned 1086 * with the bottom, so the wallpaper should extend above the top into the 1087 * status bar). 1088 */ 1089 static private class FastBitmapDrawable extends Drawable { 1090 private Bitmap mBitmap; 1091 private int mOpacity; 1092 1093 private FastBitmapDrawable(Bitmap bitmap) { 1094 mBitmap = bitmap; 1095 mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 1096 } 1097 1098 @Override 1099 public void draw(Canvas canvas) { 1100 canvas.drawBitmap( 1101 mBitmap, 1102 (getBounds().width() - mBitmap.getWidth()) / 2, 1103 (getBounds().height() - mBitmap.getHeight()), 1104 null); 1105 } 1106 1107 @Override 1108 public int getOpacity() { 1109 return mOpacity; 1110 } 1111 1112 @Override 1113 public void setAlpha(int alpha) { 1114 } 1115 1116 @Override 1117 public void setColorFilter(ColorFilter cf) { 1118 } 1119 1120 @Override 1121 public int getIntrinsicWidth() { 1122 return mBitmap.getWidth(); 1123 } 1124 1125 @Override 1126 public int getIntrinsicHeight() { 1127 return mBitmap.getHeight(); 1128 } 1129 1130 @Override 1131 public int getMinimumWidth() { 1132 return mBitmap.getWidth(); 1133 } 1134 1135 @Override 1136 public int getMinimumHeight() { 1137 return mBitmap.getHeight(); 1138 } 1139 } 1140 1141 // Everything below pertains to FaceLock - might want to separate this out 1142 1143 // Only pattern and pin unlock screens actually have a view for the FaceLock area, so it's not 1144 // uncommon for it to not exist. But if it does exist, we need to make sure it's shown (hiding 1145 // the fallback) if FaceLock is enabled, and make sure it's hidden (showing the unlock) if 1146 // FaceLock is disabled 1147 private void initializeFaceLockAreaView(View view) { 1148 mFaceLockAreaView = view.findViewById(R.id.faceLockAreaView); 1149 if (mFaceLockAreaView == null) { 1150 if (DEBUG) Log.d(TAG, "Layout does not have faceLockAreaView"); 1151 } 1152 } 1153 1154 // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops 1155 // This needs to be done in a handler because the call could be coming from a callback from the 1156 // FaceLock service that is in a thread that can't modify the UI 1157 @Override 1158 public boolean handleMessage(Message msg) { 1159 switch (msg.what) { 1160 case MSG_SHOW_FACELOCK_AREA_VIEW: 1161 if (mFaceLockAreaView != null) { 1162 mFaceLockAreaView.setVisibility(View.VISIBLE); 1163 } 1164 break; 1165 case MSG_HIDE_FACELOCK_AREA_VIEW: 1166 if (mFaceLockAreaView != null) { 1167 mFaceLockAreaView.setVisibility(View.GONE); 1168 } 1169 break; 1170 default: 1171 Log.w(TAG, "Unhandled message"); 1172 return false; 1173 } 1174 return true; 1175 } 1176 1177 // Removes show and hide messages from the message queue 1178 private void removeFaceLockAreaDisplayMessages() { 1179 mHandler.removeMessages(MSG_SHOW_FACELOCK_AREA_VIEW); 1180 mHandler.removeMessages(MSG_HIDE_FACELOCK_AREA_VIEW); 1181 } 1182 1183 // Shows the FaceLock area immediately 1184 private void showFaceLockArea() { 1185 // Remove messages to prevent a delayed hide message from undo-ing the show 1186 removeFaceLockAreaDisplayMessages(); 1187 mHandler.sendEmptyMessage(MSG_SHOW_FACELOCK_AREA_VIEW); 1188 } 1189 1190 // Hides the FaceLock area immediately 1191 private void hideFaceLockArea() { 1192 // Remove messages to prevent a delayed show message from undo-ing the hide 1193 removeFaceLockAreaDisplayMessages(); 1194 mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW); 1195 } 1196 1197 // Shows the FaceLock area for a period of time 1198 private void showFaceLockAreaWithTimeout(long timeoutMillis) { 1199 showFaceLockArea(); 1200 mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACELOCK_AREA_VIEW, timeoutMillis); 1201 } 1202 1203 // Binds to FaceLock service, but does not tell it to start 1204 public void bindToFaceLock() { 1205 if (mLockPatternUtils.usingBiometricWeak() && 1206 mLockPatternUtils.isBiometricWeakInstalled()) { 1207 if (!mBoundToFaceLockService) { 1208 if (DEBUG) Log.d(TAG, "before bind to FaceLock service"); 1209 mContext.bindService(new Intent(IFaceLockInterface.class.getName()), 1210 mFaceLockConnection, 1211 Context.BIND_AUTO_CREATE); 1212 if (DEBUG) Log.d(TAG, "after bind to FaceLock service"); 1213 mBoundToFaceLockService = true; 1214 } else { 1215 Log.w(TAG, "Attempt to bind to FaceLock when already bound"); 1216 } 1217 } 1218 } 1219 1220 // Tells FaceLock to stop and then unbinds from the FaceLock service 1221 public void stopAndUnbindFromFaceLock() { 1222 if (mLockPatternUtils.usingBiometricWeak() && 1223 mLockPatternUtils.isBiometricWeakInstalled()) { 1224 stopFaceLock(); 1225 1226 if (mBoundToFaceLockService) { 1227 if (DEBUG) Log.d(TAG, "before unbind from FaceLock service"); 1228 if (mFaceLockService != null) { 1229 try { 1230 mFaceLockService.unregisterCallback(mFaceLockCallback); 1231 } catch (RemoteException e) { 1232 // Not much we can do 1233 } 1234 } 1235 mContext.unbindService(mFaceLockConnection); 1236 if (DEBUG) Log.d(TAG, "after unbind from FaceLock service"); 1237 mBoundToFaceLockService = false; 1238 } else { 1239 // This could probably happen after the session when someone activates FaceLock 1240 // because it wasn't active when the phone was turned on 1241 Log.w(TAG, "Attempt to unbind from FaceLock when not bound"); 1242 } 1243 } 1244 } 1245 1246 private ServiceConnection mFaceLockConnection = new ServiceConnection() { 1247 // Completes connection, registers callback and starts FaceLock when service is bound 1248 @Override 1249 public void onServiceConnected(ComponentName className, IBinder iservice) { 1250 mFaceLockService = IFaceLockInterface.Stub.asInterface(iservice); 1251 if (DEBUG) Log.d(TAG, "Connected to FaceLock service"); 1252 try { 1253 mFaceLockService.registerCallback(mFaceLockCallback); 1254 } catch (RemoteException e) { 1255 Log.e(TAG, "Caught exception connecting to FaceLock: " + e.toString()); 1256 mFaceLockService = null; 1257 mBoundToFaceLockService = false; 1258 return; 1259 } 1260 1261 if (mFaceLockAreaView != null) { 1262 startFaceLock(mFaceLockAreaView.getWindowToken(), 1263 mFaceLockAreaView.getLeft(), mFaceLockAreaView.getTop(), 1264 mFaceLockAreaView.getWidth(), mFaceLockAreaView.getHeight()); 1265 } 1266 } 1267 1268 // Cleans up if FaceLock service unexpectedly disconnects 1269 @Override 1270 public void onServiceDisconnected(ComponentName className) { 1271 synchronized(mFaceLockServiceRunningLock) { 1272 mFaceLockService = null; 1273 mFaceLockServiceRunning = false; 1274 } 1275 mBoundToFaceLockService = false; 1276 Log.w(TAG, "Unexpected disconnect from FaceLock service"); 1277 } 1278 }; 1279 1280 // Tells the FaceLock service to start displaying its UI and perform recognition 1281 public void startFaceLock(IBinder windowToken, int x, int y, int h, int w) 1282 { 1283 if (mLockPatternUtils.usingBiometricWeak() && 1284 mLockPatternUtils.isBiometricWeakInstalled()) { 1285 synchronized (mFaceLockServiceRunningLock) { 1286 if (!mFaceLockServiceRunning) { 1287 if (DEBUG) Log.d(TAG, "Starting FaceLock"); 1288 try { 1289 mFaceLockService.startUi(windowToken, x, y, h, w); 1290 } catch (RemoteException e) { 1291 Log.e(TAG, "Caught exception starting FaceLock: " + e.toString()); 1292 return; 1293 } 1294 mFaceLockServiceRunning = true; 1295 } else { 1296 if (DEBUG) Log.w(TAG, "startFaceLock() attempted while running"); 1297 } 1298 } 1299 } 1300 } 1301 1302 // Tells the FaceLock service to stop displaying its UI and stop recognition 1303 public void stopFaceLock() 1304 { 1305 if (mLockPatternUtils.usingBiometricWeak() && 1306 mLockPatternUtils.isBiometricWeakInstalled()) { 1307 // Note that attempting to stop FaceLock when it's not running is not an issue. 1308 // FaceLock can return, which stops it and then we try to stop it when the 1309 // screen is turned off. That's why we check. 1310 synchronized (mFaceLockServiceRunningLock) { 1311 if (mFaceLockServiceRunning) { 1312 try { 1313 if (DEBUG) Log.d(TAG, "Stopping FaceLock"); 1314 mFaceLockService.stopUi(); 1315 } catch (RemoteException e) { 1316 Log.e(TAG, "Caught exception stopping FaceLock: " + e.toString()); 1317 } 1318 mFaceLockServiceRunning = false; 1319 } 1320 } 1321 } 1322 } 1323 1324 // Implements the FaceLock service callback interface defined in AIDL 1325 private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() { 1326 1327 // Stops the FaceLock UI and indicates that the phone should be unlocked 1328 @Override 1329 public void unlock() { 1330 if (DEBUG) Log.d(TAG, "FaceLock unlock()"); 1331 showFaceLockArea(); // Keep fallback covered 1332 stopFaceLock(); 1333 1334 mKeyguardScreenCallback.keyguardDone(true); 1335 mKeyguardScreenCallback.reportSuccessfulUnlockAttempt(); 1336 } 1337 1338 // Stops the FaceLock UI and exposes the backup method without unlocking 1339 // This means the user has cancelled out 1340 @Override 1341 public void cancel() { 1342 if (DEBUG) Log.d(TAG, "FaceLock cancel()"); 1343 hideFaceLockArea(); // Expose fallback 1344 stopFaceLock(); 1345 mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT); 1346 } 1347 1348 // Stops the FaceLock UI and exposes the backup method without unlocking 1349 // This means FaceLock failed to recognize them 1350 @Override 1351 public void reportFailedAttempt() { 1352 if (DEBUG) Log.d(TAG, "FaceLock reportFailedAttempt()"); 1353 mFailedFaceUnlockAttempts++; 1354 hideFaceLockArea(); // Expose fallback 1355 stopFaceLock(); 1356 mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT); 1357 } 1358 1359 // Allows the Face Unlock service to poke the wake lock to keep the lockscreen alive 1360 @Override 1361 public void pokeWakelock() { 1362 if (DEBUG) Log.d(TAG, "FaceLock pokeWakelock()"); 1363 mKeyguardScreenCallback.pokeWakelock(); 1364 } 1365 }; 1366} 1367