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