KeyguardHostView.java revision dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4b
1/* 2 * Copyright (C) 2012 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.keyguard; 18 19import android.app.Activity; 20import android.app.ActivityManager; 21import android.app.ActivityOptions; 22import android.app.AlertDialog; 23import android.app.admin.DevicePolicyManager; 24import android.appwidget.AppWidgetHost; 25import android.appwidget.AppWidgetHostView; 26import android.appwidget.AppWidgetManager; 27import android.appwidget.AppWidgetProviderInfo; 28import android.content.Context; 29import android.content.Intent; 30import android.content.IntentSender; 31import android.content.pm.UserInfo; 32import android.content.res.Resources; 33import android.graphics.Canvas; 34import android.graphics.Rect; 35import android.os.Looper; 36import android.os.Parcel; 37import android.os.Parcelable; 38import android.os.UserHandle; 39import android.os.UserManager; 40import android.provider.Settings; 41import android.util.AttributeSet; 42import android.util.Log; 43import android.util.Slog; 44import android.view.KeyEvent; 45import android.view.LayoutInflater; 46import android.view.MotionEvent; 47import android.view.View; 48import android.view.WindowManager; 49import android.view.animation.AnimationUtils; 50import android.widget.RemoteViews.OnClickHandler; 51import android.widget.TextView; 52 53import com.android.internal.R; 54import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode; 55import com.android.internal.widget.LockPatternUtils; 56 57import java.io.File; 58import java.util.List; 59 60public class KeyguardHostView extends KeyguardViewBase { 61 private static final String TAG = "KeyguardViewHost"; 62 63 // Use this to debug all of keyguard 64 public static boolean DEBUG; 65 66 // also referenced in SecuritySettings.java 67 static final int APPWIDGET_HOST_ID = 0x4B455947; 68 69 // transport control states 70 private static final int TRANSPORT_GONE = 0; 71 private static final int TRANSPORT_INVISIBLE = 1; 72 private static final int TRANSPORT_VISIBLE = 2; 73 74 private AppWidgetHost mAppWidgetHost; 75 private KeyguardWidgetPager mAppWidgetContainer; 76 private KeyguardSecurityViewFlipper mSecurityViewContainer; 77 private KeyguardSelectorView mKeyguardSelectorView; 78 private KeyguardTransportControlView mTransportControl; 79 private boolean mEnableMenuKey; 80 private boolean mIsVerifyUnlockOnly; 81 private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView 82 private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; 83 84 protected Runnable mLaunchRunnable; 85 86 protected int mFailedAttempts; 87 private LockPatternUtils mLockPatternUtils; 88 89 private KeyguardSecurityModel mSecurityModel; 90 private KeyguardViewStateManager mViewStateManager; 91 92 private Rect mTempRect = new Rect(); 93 private int mTransportState = TRANSPORT_GONE; 94 95 /*package*/ interface TransportCallback { 96 void onListenerDetached(); 97 void onListenerAttached(); 98 void onPlayStateChanged(); 99 } 100 101 /*package*/ interface UserSwitcherCallback { 102 void hideSecurityView(int duration); 103 void showSecurityView(); 104 void showUnlockHint(); 105 void userActivity(); 106 } 107 108 public KeyguardHostView(Context context) { 109 this(context, null); 110 } 111 112 public KeyguardHostView(Context context, AttributeSet attrs) { 113 super(context, attrs); 114 mLockPatternUtils = new LockPatternUtils(context); 115 mAppWidgetHost = new AppWidgetHost( 116 context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); 117 mSecurityModel = new KeyguardSecurityModel(context); 118 119 // The following enables the MENU key to work for testing automation 120 mEnableMenuKey = shouldEnableMenuKey(); 121 setFocusable(true); 122 setFocusableInTouchMode(true); 123 } 124 125 @Override 126 public boolean onTouchEvent(MotionEvent ev) { 127 boolean result = super.onTouchEvent(ev); 128 mTempRect.set(0, 0, 0, 0); 129 offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect); 130 ev.offsetLocation(mTempRect.left, mTempRect.top); 131 result = mSecurityViewContainer.dispatchTouchEvent(ev) || result; 132 ev.offsetLocation(-mTempRect.left, -mTempRect.top); 133 return result; 134 } 135 136 @Override 137 protected void dispatchDraw(Canvas canvas) { 138 super.dispatchDraw(canvas); 139 if (mViewMediatorCallback != null) { 140 mViewMediatorCallback.keyguardDoneDrawing(); 141 } 142 } 143 144 private int getWidgetPosition(int id) { 145 final int children = mAppWidgetContainer.getChildCount(); 146 for (int i = 0; i < children; i++) { 147 if (mAppWidgetContainer.getChildAt(i).getId() == id) { 148 return i; 149 } 150 } 151 return -1; 152 } 153 154 @Override 155 protected void onFinishInflate() { 156 // Grab instances of and make any necessary changes to the main layouts. Create 157 // view state manager and wire up necessary listeners / callbacks. 158 mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container); 159 mAppWidgetContainer.setVisibility(VISIBLE); 160 mAppWidgetContainer.setCallbacks(mWidgetCallbacks); 161 mAppWidgetContainer.setMinScale(0.5f); 162 163 addDefaultWidgets(); 164 maybePopulateWidgets(); 165 166 mViewStateManager = new KeyguardViewStateManager(); 167 SlidingChallengeLayout slider = 168 (SlidingChallengeLayout) findViewById(R.id.sliding_layout); 169 if (slider != null) { 170 slider.setOnChallengeScrolledListener(mViewStateManager); 171 } 172 mAppWidgetContainer.setViewStateManager(mViewStateManager); 173 174 mViewStateManager.setPagedView(mAppWidgetContainer); 175 mViewStateManager.setChallengeLayout(slider != null ? slider : 176 (ChallengeLayout) findViewById(R.id.multi_pane_challenge)); 177 mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper); 178 mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view); 179 mViewStateManager.setSecurityViewContainer(mSecurityViewContainer); 180 181 mViewStateManager.showUsabilityHints(); 182 183 updateSecurityViews(); 184 if (!(mContext instanceof Activity)) { 185 setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK); 186 } 187 188 if (KeyguardUpdateMonitor.getInstance(mContext).getIsFirstBoot()) { 189 showPrimarySecurityScreen(false); 190 } 191 } 192 193 private void updateSecurityViews() { 194 int children = mSecurityViewContainer.getChildCount(); 195 for (int i = 0; i < children; i++) { 196 updateSecurityView(mSecurityViewContainer.getChildAt(i)); 197 } 198 } 199 200 private void updateSecurityView(View view) { 201 if (view instanceof KeyguardSecurityView) { 202 KeyguardSecurityView ksv = (KeyguardSecurityView) view; 203 ksv.setKeyguardCallback(mCallback); 204 ksv.setLockPatternUtils(mLockPatternUtils); 205 } else { 206 Log.w(TAG, "View " + view + " is not a KeyguardSecurityView"); 207 } 208 } 209 210 void setLockPatternUtils(LockPatternUtils utils) { 211 mSecurityModel.setLockPatternUtils(utils); 212 mLockPatternUtils = utils; 213 updateSecurityViews(); 214 } 215 216 @Override 217 protected void onAttachedToWindow() { 218 super.onAttachedToWindow(); 219 mAppWidgetHost.startListening(); 220 post(mSwitchPageRunnable); 221 } 222 223 @Override 224 protected void onDetachedFromWindow() { 225 super.onDetachedFromWindow(); 226 mAppWidgetHost.stopListening(); 227 } 228 229 private AppWidgetHost getAppWidgetHost() { 230 return mAppWidgetHost; 231 } 232 233 void addWidget(AppWidgetHostView view, int pageIndex) { 234 mAppWidgetContainer.addWidget(view, pageIndex); 235 } 236 237 private KeyguardWidgetPager.Callbacks mWidgetCallbacks 238 = new KeyguardWidgetPager.Callbacks() { 239 @Override 240 public void userActivity() { 241 if (mViewMediatorCallback != null) { 242 mViewMediatorCallback.userActivity(); 243 } 244 } 245 246 @Override 247 public void onUserActivityTimeoutChanged() { 248 if (mViewMediatorCallback != null) { 249 mViewMediatorCallback.onUserActivityTimeoutChanged(); 250 } 251 } 252 }; 253 254 @Override 255 public long getUserActivityTimeout() { 256 // Currently only considering user activity timeouts needed by widgets. 257 // Could also take into account longer timeouts for certain security views. 258 if (mAppWidgetContainer != null) { 259 return mAppWidgetContainer.getUserActivityTimeout(); 260 } 261 return -1; 262 } 263 264 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { 265 266 public void userActivity(long timeout) { 267 if (mViewMediatorCallback != null) { 268 mViewMediatorCallback.userActivity(timeout); 269 } 270 } 271 272 public void dismiss(boolean authenticated) { 273 showNextSecurityScreenOrFinish(authenticated); 274 } 275 276 public boolean isVerifyUnlockOnly() { 277 return mIsVerifyUnlockOnly; 278 } 279 280 public void reportSuccessfulUnlockAttempt() { 281 KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts(); 282 mLockPatternUtils.reportSuccessfulPasswordAttempt(); 283 } 284 285 public void reportFailedUnlockAttempt() { 286 if (mCurrentSecuritySelection == SecurityMode.Biometric) { 287 KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt(); 288 } else { 289 KeyguardHostView.this.reportFailedUnlockAttempt(); 290 } 291 } 292 293 public int getFailedAttempts() { 294 return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(); 295 } 296 297 @Override 298 public void showBackupSecurity() { 299 KeyguardHostView.this.showBackupSecurityScreen(); 300 } 301 302 @Override 303 public void setOnDismissRunnable(Runnable runnable) { 304 KeyguardHostView.this.setOnDismissRunnable(runnable); 305 } 306 307 }; 308 309 private void showDialog(String title, String message) { 310 final AlertDialog dialog = new AlertDialog.Builder(mContext) 311 .setTitle(title) 312 .setMessage(message) 313 .setNeutralButton(com.android.internal.R.string.ok, null) 314 .create(); 315 if (!(mContext instanceof Activity)) { 316 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 317 } 318 dialog.show(); 319 } 320 321 private void showTimeoutDialog() { 322 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 323 int messageId = 0; 324 325 switch (mSecurityModel.getSecurityMode()) { 326 case Pattern: 327 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message; 328 break; 329 case PIN: 330 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message; 331 break; 332 case Password: 333 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message; 334 break; 335 } 336 337 if (messageId != 0) { 338 final String message = mContext.getString(messageId, 339 KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(), 340 timeoutInSeconds); 341 showDialog(null, message); 342 } 343 } 344 345 private void showAlmostAtWipeDialog(int attempts, int remaining) { 346 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 347 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe, 348 attempts, remaining); 349 showDialog(null, message); 350 } 351 352 private void showWipeDialog(int attempts) { 353 String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts); 354 showDialog(null, message); 355 } 356 357 private void showAlmostAtAccountLoginDialog() { 358 final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 359 final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 360 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 361 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login, 362 count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); 363 showDialog(null, message); 364 } 365 366 private void reportFailedUnlockAttempt() { 367 final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); 368 final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time 369 370 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); 371 372 SecurityMode mode = mSecurityModel.getSecurityMode(); 373 final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern; 374 375 final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager() 376 .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser()); 377 378 final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 379 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 380 381 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? 382 (failedAttemptsBeforeWipe - failedAttempts) 383 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction 384 385 boolean showTimeout = false; 386 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { 387 // If we reach this code, it means the user has installed a DevicePolicyManager 388 // that requests device wipe after N attempts. Once we get below the grace 389 // period, we'll post this dialog every time as a clear warning until the 390 // bombshell hits and the device is wiped. 391 if (remainingBeforeWipe > 0) { 392 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe); 393 } else { 394 // Too many attempts. The device will be wiped shortly. 395 Slog.i(TAG, "Too many unlock attempts; device will be wiped!"); 396 showWipeDialog(failedAttempts); 397 } 398 } else { 399 showTimeout = 400 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0; 401 if (usingPattern && mEnableFallback) { 402 if (failedAttempts == failedAttemptWarning) { 403 showAlmostAtAccountLoginDialog(); 404 showTimeout = false; // don't show both dialogs 405 } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { 406 mLockPatternUtils.setPermanentlyLocked(true); 407 showSecurityScreen(SecurityMode.Account); 408 // don't show timeout dialog because we show account unlock screen next 409 showTimeout = false; 410 } 411 } 412 } 413 monitor.reportFailedUnlockAttempt(); 414 mLockPatternUtils.reportFailedPasswordAttempt(); 415 if (showTimeout) { 416 showTimeoutDialog(); 417 } 418 } 419 420 /** 421 * Shows the primary security screen for the user. This will be either the multi-selector 422 * or the user's security method. 423 * @param turningOff true if the device is being turned off 424 */ 425 void showPrimarySecurityScreen(boolean turningOff) { 426 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 427 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); 428 if (!turningOff && KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) { 429 // If we're not turning off, then allow biometric alternate. 430 // We'll reload it when the device comes back on. 431 securityMode = mSecurityModel.getAlternateFor(securityMode); 432 } 433 showSecurityScreen(securityMode); 434 } 435 436 /** 437 * Shows the backup security screen for the current security mode. This could be used for 438 * password recovery screens but is currently only used for pattern unlock to show the 439 * account unlock screen and biometric unlock to show the user's normal unlock. 440 */ 441 private void showBackupSecurityScreen() { 442 if (DEBUG) Log.d(TAG, "showBackupSecurity()"); 443 SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection); 444 showSecurityScreen(backup); 445 } 446 447 public boolean showNextSecurityScreenIfPresent() { 448 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 449 // Allow an alternate, such as biometric unlock 450 securityMode = mSecurityModel.getAlternateFor(securityMode); 451 if (SecurityMode.None == securityMode) { 452 return false; 453 } else { 454 showSecurityScreen(securityMode); // switch to the alternate security view 455 return true; 456 } 457 } 458 459 private void showNextSecurityScreenOrFinish(boolean authenticated) { 460 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); 461 boolean finish = false; 462 if (SecurityMode.None == mCurrentSecuritySelection) { 463 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 464 // Allow an alternate, such as biometric unlock 465 securityMode = mSecurityModel.getAlternateFor(securityMode); 466 if (SecurityMode.None == securityMode) { 467 finish = true; // no security required 468 } else { 469 showSecurityScreen(securityMode); // switch to the alternate security view 470 } 471 } else if (authenticated) { 472 switch (mCurrentSecuritySelection) { 473 case Pattern: 474 case Password: 475 case PIN: 476 case Account: 477 case Biometric: 478 finish = true; 479 break; 480 481 case SimPin: 482 case SimPuk: 483 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home 484 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 485 if (securityMode != SecurityMode.None) { 486 showSecurityScreen(securityMode); 487 } else { 488 finish = true; 489 } 490 break; 491 492 default: 493 Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe"); 494 showPrimarySecurityScreen(false); 495 break; 496 } 497 } else { 498 showPrimarySecurityScreen(false); 499 } 500 if (finish) { 501 // If the alternate unlock was suppressed, it can now be safely 502 // enabled because the user has left keyguard. 503 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); 504 KeyguardUpdateMonitor.getInstance(mContext).setIsFirstBoot(false); 505 506 // If there's a pending runnable because the user interacted with a widget 507 // and we're leaving keyguard, then run it. 508 if (mLaunchRunnable != null) { 509 mLaunchRunnable.run(); 510 mLaunchRunnable = null; 511 } 512 if (mViewMediatorCallback != null) { 513 mViewMediatorCallback.keyguardDone(true); 514 } 515 } else { 516 mViewStateManager.showBouncer(true); 517 } 518 } 519 520 private OnClickHandler mOnClickHandler = new OnClickHandler() { 521 @Override 522 public boolean onClickHandler(final View view, 523 final android.app.PendingIntent pendingIntent, 524 final Intent fillInIntent) { 525 if (pendingIntent.isActivity()) { 526 setOnDismissRunnable(new Runnable() { 527 public void run() { 528 try { 529 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? 530 Context context = view.getContext(); 531 ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, 532 0, 0, 533 view.getMeasuredWidth(), view.getMeasuredHeight()); 534 context.startIntentSender( 535 pendingIntent.getIntentSender(), fillInIntent, 536 Intent.FLAG_ACTIVITY_NEW_TASK, 537 Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle()); 538 } catch (IntentSender.SendIntentException e) { 539 android.util.Log.e(TAG, "Cannot send pending intent: ", e); 540 } catch (Exception e) { 541 android.util.Log.e(TAG, "Cannot send pending intent due to " + 542 "unknown exception: ", e); 543 } 544 } 545 }); 546 547 mCallback.dismiss(false); 548 return true; 549 } else { 550 return super.onClickHandler(view, pendingIntent, fillInIntent); 551 } 552 }; 553 }; 554 555 private KeyguardStatusViewManager mKeyguardStatusViewManager; 556 557 // Used to ignore callbacks from methods that are no longer current (e.g. face unlock). 558 // This avoids unwanted asynchronous events from messing with the state. 559 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { 560 561 @Override 562 public void userActivity(long timeout) { 563 } 564 565 @Override 566 public void showBackupSecurity() { 567 } 568 569 @Override 570 public void setOnDismissRunnable(Runnable runnable) { 571 } 572 573 @Override 574 public void reportSuccessfulUnlockAttempt() { 575 } 576 577 @Override 578 public void reportFailedUnlockAttempt() { 579 } 580 581 @Override 582 public boolean isVerifyUnlockOnly() { 583 return false; 584 } 585 586 @Override 587 public int getFailedAttempts() { 588 return 0; 589 } 590 591 @Override 592 public void dismiss(boolean securityVerified) { 593 } 594 }; 595 596 @Override 597 public void reset() { 598 mIsVerifyUnlockOnly = false; 599 mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_status_view)); 600 } 601 602 /** 603 * Sets a runnable to run when keyguard is dismissed 604 * @param runnable 605 */ 606 protected void setOnDismissRunnable(Runnable runnable) { 607 mLaunchRunnable = runnable; 608 } 609 610 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { 611 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 612 KeyguardSecurityView view = null; 613 final int children = mSecurityViewContainer.getChildCount(); 614 for (int child = 0; child < children; child++) { 615 if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) { 616 view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child)); 617 break; 618 } 619 } 620 boolean simPukFullScreen = getResources().getBoolean( 621 com.android.internal.R.bool.kg_sim_puk_account_full_screen); 622 int layoutId = getLayoutIdFor(securityMode); 623 if (view == null && layoutId != 0) { 624 final LayoutInflater inflater = LayoutInflater.from(mContext); 625 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); 626 View v = inflater.inflate(layoutId, this, false); 627 mSecurityViewContainer.addView(v); 628 updateSecurityView(v); 629 630 view = (KeyguardSecurityView) v; 631 TextView navigationText = ((TextView) findViewById(R.id.keyguard_message_area)); 632 633 // Some devices can fit a navigation area, others cannot. On devices that cannot, 634 // we display the security message in status area. 635 if (navigationText != null) { 636 view.setSecurityMessageDisplay(new KeyguardNavigationManager(navigationText)); 637 } else { 638 view.setSecurityMessageDisplay(mKeyguardStatusViewManager); 639 } 640 } 641 642 if (securityMode == SecurityMode.SimPin || securityMode == SecurityMode.SimPuk || 643 securityMode == SecurityMode.Account) { 644 if (simPukFullScreen) { 645 mAppWidgetContainer.setVisibility(View.GONE); 646 } 647 } 648 649 if (view instanceof KeyguardSelectorView) { 650 KeyguardSelectorView selectorView = (KeyguardSelectorView) view; 651 View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container); 652 selectorView.setCarrierArea(carrierText); 653 } 654 655 return view; 656 } 657 658 /** 659 * Switches to the given security view unless it's already being shown, in which case 660 * this is a no-op. 661 * 662 * @param securityMode 663 */ 664 private void showSecurityScreen(SecurityMode securityMode) { 665 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); 666 667 if (securityMode == mCurrentSecuritySelection) return; 668 669 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); 670 KeyguardSecurityView newView = getSecurityView(securityMode); 671 672 // Emulate Activity life cycle 673 if (oldView != null) { 674 oldView.onPause(); 675 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view 676 } 677 newView.onResume(); 678 newView.setKeyguardCallback(mCallback); 679 680 final boolean needsInput = newView.needsInput(); 681 if (mViewMediatorCallback != null) { 682 mViewMediatorCallback.setNeedsInput(needsInput); 683 } 684 685 // Find and show this child. 686 final int childCount = mSecurityViewContainer.getChildCount(); 687 688 // Do flip animation to the next screen 689 if (false) { 690 mSecurityViewContainer.setInAnimation( 691 AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_in)); 692 mSecurityViewContainer.setOutAnimation( 693 AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_out)); 694 } 695 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 696 for (int i = 0; i < childCount; i++) { 697 if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) { 698 mSecurityViewContainer.setDisplayedChild(i); 699 break; 700 } 701 } 702 703 if (securityMode == SecurityMode.None) { 704 // Discard current runnable if we're switching back to the selector view 705 setOnDismissRunnable(null); 706 } 707 mCurrentSecuritySelection = securityMode; 708 } 709 710 @Override 711 public void onScreenTurnedOn() { 712 if (DEBUG) Log.d(TAG, "screen on"); 713 showPrimarySecurityScreen(false); 714 getSecurityView(mCurrentSecuritySelection).onResume(); 715 716 // This is a an attempt to fix bug 7137389 where the device comes back on but the entire 717 // layout is blank but forcing a layout causes it to reappear (e.g. with with 718 // hierarchyviewer). 719 requestLayout(); 720 721 if (mViewStateManager != null) { 722 mViewStateManager.showUsabilityHints(); 723 } 724 } 725 726 @Override 727 public void onScreenTurnedOff() { 728 if (DEBUG) Log.d(TAG, "screen off"); 729 showPrimarySecurityScreen(true); 730 getSecurityView(mCurrentSecuritySelection).onPause(); 731 } 732 733 @Override 734 public void show() { 735 if (DEBUG) Log.d(TAG, "show()"); 736 showPrimarySecurityScreen(false); 737 } 738 739 private boolean isSecure() { 740 SecurityMode mode = mSecurityModel.getSecurityMode(); 741 switch (mode) { 742 case Pattern: 743 return mLockPatternUtils.isLockPatternEnabled(); 744 case Password: 745 case PIN: 746 return mLockPatternUtils.isLockPasswordEnabled(); 747 case SimPin: 748 case SimPuk: 749 case Account: 750 return true; 751 case None: 752 return false; 753 default: 754 throw new IllegalStateException("Unknown security mode " + mode); 755 } 756 } 757 758 @Override 759 public void wakeWhenReadyTq(int keyCode) { 760 if (DEBUG) Log.d(TAG, "onWakeKey"); 761 if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) { 762 if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); 763 showSecurityScreen(SecurityMode.None); 764 } else { 765 if (DEBUG) Log.d(TAG, "poking wake lock immediately"); 766 } 767 if (mViewMediatorCallback != null) { 768 mViewMediatorCallback.wakeUp(); 769 } 770 } 771 772 @Override 773 public void verifyUnlock() { 774 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 775 if (securityMode == KeyguardSecurityModel.SecurityMode.None) { 776 if (mViewMediatorCallback != null) { 777 mViewMediatorCallback.keyguardDone(true); 778 } 779 } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern 780 && securityMode != KeyguardSecurityModel.SecurityMode.PIN 781 && securityMode != KeyguardSecurityModel.SecurityMode.Password) { 782 // can only verify unlock when in pattern/password mode 783 if (mViewMediatorCallback != null) { 784 mViewMediatorCallback.keyguardDone(false); 785 } 786 } else { 787 // otherwise, go to the unlock screen, see if they can verify it 788 mIsVerifyUnlockOnly = true; 789 showSecurityScreen(securityMode); 790 } 791 } 792 793 private int getSecurityViewIdForMode(SecurityMode securityMode) { 794 switch (securityMode) { 795 case None: return R.id.keyguard_selector_view; 796 case Pattern: return R.id.keyguard_pattern_view; 797 case PIN: return R.id.keyguard_pin_view; 798 case Password: return R.id.keyguard_password_view; 799 case Biometric: return R.id.keyguard_face_unlock_view; 800 case Account: return R.id.keyguard_account_view; 801 case SimPin: return R.id.keyguard_sim_pin_view; 802 case SimPuk: return R.id.keyguard_sim_puk_view; 803 } 804 return 0; 805 } 806 807 private int getLayoutIdFor(SecurityMode securityMode) { 808 switch (securityMode) { 809 case None: return R.layout.keyguard_selector_view; 810 case Pattern: return R.layout.keyguard_pattern_view; 811 case PIN: return R.layout.keyguard_pin_view; 812 case Password: return R.layout.keyguard_password_view; 813 case Biometric: return R.layout.keyguard_face_unlock_view; 814 case Account: return R.layout.keyguard_account_view; 815 case SimPin: return R.layout.keyguard_sim_pin_view; 816 case SimPuk: return R.layout.keyguard_sim_puk_view; 817 default: 818 return 0; 819 } 820 } 821 822 private void addWidget(int appId, int pageIndex) { 823 AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); 824 AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId); 825 if (appWidgetInfo != null) { 826 AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo); 827 addWidget(view, pageIndex); 828 } else { 829 Log.w(TAG, "AppWidgetInfo was null; not adding widget id " + appId); 830 } 831 } 832 833 private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks = 834 new CameraWidgetFrame.Callbacks() { 835 @Override 836 public void onLaunchingCamera() { 837 SlidingChallengeLayout slider = locateSlider(); 838 if (slider != null) { 839 slider.showHandle(false); 840 } 841 } 842 843 @Override 844 public void onCameraLaunched() { 845 SlidingChallengeLayout slider = locateSlider(); 846 if (slider != null) { 847 slider.showHandle(true); 848 } 849 mAppWidgetContainer.scrollLeft(); 850 } 851 852 private SlidingChallengeLayout locateSlider() { 853 return (SlidingChallengeLayout) findViewById(R.id.sliding_layout); 854 } 855 }; 856 857 private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { 858 @Override 859 Context getContext() { 860 return mContext; 861 } 862 863 @Override 864 KeyguardSecurityCallback getCallback() { 865 return mCallback; 866 } 867 868 @Override 869 LockPatternUtils getLockPatternUtils() { 870 return mLockPatternUtils; 871 }}; 872 873 private void addDefaultWidgets() { 874 LayoutInflater inflater = LayoutInflater.from(mContext); 875 inflater.inflate(R.layout.keyguard_transport_control_view, this, true); 876 877 View addWidget = inflater.inflate(R.layout.keyguard_add_widget, null, true); 878 mAppWidgetContainer.addWidget(addWidget); 879 View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true); 880 mAppWidgetContainer.addWidget(statusWidget); 881 if (mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) { 882 View cameraWidget = 883 CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher); 884 if (cameraWidget != null) { 885 mAppWidgetContainer.addWidget(cameraWidget); 886 } 887 } 888 889 View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view); 890 addWidgetButton.setOnClickListener(new OnClickListener() { 891 @Override 892 public void onClick(View v) { 893 mCallback.setOnDismissRunnable(new Runnable() { 894 895 @Override 896 public void run() { 897 Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS); 898 intent.addFlags( 899 Intent.FLAG_ACTIVITY_NEW_TASK 900 | Intent.FLAG_ACTIVITY_SINGLE_TOP 901 | Intent.FLAG_ACTIVITY_CLEAR_TOP 902 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 903 mContext.startActivityAsUser(intent, 904 new UserHandle(UserHandle.USER_CURRENT)); 905 } 906 }); 907 mCallback.dismiss(false); 908 } 909 }); 910 911 enableUserSelectorIfNecessary(); 912 initializeTransportControl(); 913 } 914 915 private void initializeTransportControl() { 916 mTransportControl = 917 (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control); 918 mTransportControl.setVisibility(View.GONE); 919 920 // This code manages showing/hiding the transport control. We keep it around and only 921 // add it to the hierarchy if it needs to be present. 922 if (mTransportControl != null) { 923 mTransportControl.setKeyguardCallback(new TransportCallback() { 924 @Override 925 public void onListenerDetached() { 926 int page = getWidgetPosition(R.id.keyguard_transport_control); 927 if (page != -1) { 928 mAppWidgetContainer.removeView(mTransportControl); 929 // XXX keep view attached so we still get show/hide events from AudioManager 930 KeyguardHostView.this.addView(mTransportControl); 931 mTransportControl.setVisibility(View.GONE); 932 mTransportState = TRANSPORT_GONE; 933 mTransportControl.post(mSwitchPageRunnable); 934 } 935 } 936 937 @Override 938 public void onListenerAttached() { 939 if (getWidgetPosition(R.id.keyguard_transport_control) == -1) { 940 KeyguardHostView.this.removeView(mTransportControl); 941 mAppWidgetContainer.addView(mTransportControl, 0); 942 mTransportControl.setVisibility(View.VISIBLE); 943 } 944 } 945 946 @Override 947 public void onPlayStateChanged() { 948 mTransportControl.post(mSwitchPageRunnable); 949 } 950 }); 951 } 952 953 mKeyguardStatusViewManager = ((KeyguardStatusView) 954 findViewById(R.id.keyguard_status_view_face_palm)).getManager(); 955 956 } 957 958 private void maybePopulateWidgets() { 959 DevicePolicyManager dpm = 960 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 961 if (dpm != null) { 962 final int currentUser = mLockPatternUtils.getCurrentUser(); 963 final int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser); 964 if ((disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) { 965 Log.v(TAG, "Keyguard widgets disabled because of device policy admin"); 966 return; 967 } 968 } 969 970 View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget); 971 int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget); 972 // This shouldn't happen, but just to be safe! 973 if (addPageIndex < 0) { 974 addPageIndex = 0; 975 } 976 977 // Add user-selected widget 978 final int[] widgets = mLockPatternUtils.getAppWidgets(); 979 if (widgets == null) { 980 Log.d(TAG, "Problem reading widgets"); 981 } else { 982 for (int i = widgets.length -1; i >= 0; i--) { 983 if (widgets[i] != -1) { 984 // We add the widgets from left to right, starting after the first page after 985 // the add page. We count down, since the order will be persisted from right 986 // to left, starting after camera. 987 addWidget(widgets[i], addPageIndex + 1); 988 } 989 } 990 } 991 } 992 993 Runnable mSwitchPageRunnable = new Runnable() { 994 @Override 995 public void run() { 996 showAppropriateWidgetPage(); 997 } 998 }; 999 1000 static class SavedState extends BaseSavedState { 1001 int transportState; 1002 1003 SavedState(Parcelable superState) { 1004 super(superState); 1005 } 1006 1007 private SavedState(Parcel in) { 1008 super(in); 1009 this.transportState = in.readInt(); 1010 } 1011 1012 @Override 1013 public void writeToParcel(Parcel out, int flags) { 1014 super.writeToParcel(out, flags); 1015 out.writeInt(this.transportState); 1016 } 1017 1018 public static final Parcelable.Creator<SavedState> CREATOR 1019 = new Parcelable.Creator<SavedState>() { 1020 public SavedState createFromParcel(Parcel in) { 1021 return new SavedState(in); 1022 } 1023 1024 public SavedState[] newArray(int size) { 1025 return new SavedState[size]; 1026 } 1027 }; 1028 } 1029 1030 @Override 1031 public Parcelable onSaveInstanceState() { 1032 Parcelable superState = super.onSaveInstanceState(); 1033 SavedState ss = new SavedState(superState); 1034 ss.transportState = mTransportState; 1035 return ss; 1036 } 1037 1038 @Override 1039 public void onRestoreInstanceState(Parcelable state) { 1040 if (!(state instanceof SavedState)) { 1041 super.onRestoreInstanceState(state); 1042 return; 1043 } 1044 SavedState ss = (SavedState) state; 1045 super.onRestoreInstanceState(ss.getSuperState()); 1046 mTransportState = ss.transportState; 1047 post(mSwitchPageRunnable); 1048 } 1049 1050 private void showAppropriateWidgetPage() { 1051 1052 // The following sets the priority for showing widgets. Transport should be shown if 1053 // music is playing, followed by the multi-user widget if enabled, followed by the 1054 // status widget. 1055 final int pageToShow; 1056 if (mTransportControl.isMusicPlaying() || mTransportState == TRANSPORT_VISIBLE) { 1057 mTransportState = TRANSPORT_VISIBLE; 1058 pageToShow = mAppWidgetContainer.indexOfChild(mTransportControl); 1059 } else { 1060 UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1061 final View multiUserView = findViewById(R.id.keyguard_multi_user_selector); 1062 final int multiUserPosition = mAppWidgetContainer.indexOfChild(multiUserView); 1063 if (multiUserPosition != -1 && mUm.getUsers(true).size() > 1) { 1064 pageToShow = multiUserPosition; 1065 } else { 1066 final View statusView = findViewById(R.id.keyguard_status_view); 1067 pageToShow = mAppWidgetContainer.indexOfChild(statusView); 1068 } 1069 if (mTransportState == TRANSPORT_VISIBLE) { 1070 mTransportState = TRANSPORT_INVISIBLE; 1071 } 1072 } 1073 mAppWidgetContainer.setCurrentPage(pageToShow); 1074 } 1075 1076 private void enableUserSelectorIfNecessary() { 1077 // if there are multiple users, we need to add the multi-user switcher widget to the 1078 // keyguard. 1079 UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1080 List<UserInfo> users = mUm.getUsers(true); 1081 1082 if (users.size() > 1) { 1083 KeyguardMultiUserSelectorView multiUser = 1084 (KeyguardMultiUserSelectorView) findViewById(R.id.keyguard_user_selector); 1085 multiUser.setVisibility(View.VISIBLE); 1086 multiUser.addUsers(mUm.getUsers(true)); 1087 UserSwitcherCallback callback = new UserSwitcherCallback() { 1088 @Override 1089 public void hideSecurityView(int duration) { 1090 mSecurityViewContainer.animate().alpha(0).setDuration(duration); 1091 } 1092 1093 @Override 1094 public void showSecurityView() { 1095 mSecurityViewContainer.setAlpha(1.0f); 1096 } 1097 1098 @Override 1099 public void showUnlockHint() { 1100 if (mKeyguardSelectorView != null) { 1101 mKeyguardSelectorView.showUsabilityHint(); 1102 } 1103 } 1104 1105 @Override 1106 public void userActivity() { 1107 if (mViewMediatorCallback != null) { 1108 mViewMediatorCallback.userActivity(); 1109 } 1110 } 1111 }; 1112 multiUser.setCallback(callback); 1113 } 1114 } 1115 1116 @Override 1117 public void cleanUp() { 1118 1119 } 1120 1121 /** 1122 * In general, we enable unlocking the insecure keyguard with the menu key. However, there are 1123 * some cases where we wish to disable it, notably when the menu button placement or technology 1124 * is prone to false positives. 1125 * 1126 * @return true if the menu key should be enabled 1127 */ 1128 private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; 1129 private boolean shouldEnableMenuKey() { 1130 final Resources res = getResources(); 1131 final boolean configDisabled = res.getBoolean( 1132 com.android.internal.R.bool.config_disableMenuKeyInLockScreen); 1133 final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); 1134 final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); 1135 return !configDisabled || isTestHarness || fileOverride; 1136 } 1137 1138 @Override 1139 public boolean onKeyDown(int keyCode, KeyEvent event) { 1140 if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKey) { 1141 showNextSecurityScreenOrFinish(false); 1142 return true; 1143 } else { 1144 return super.onKeyDown(keyCode, event); 1145 } 1146 } 1147 1148 public void goToUserSwitcher() { 1149 mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector)); 1150 } 1151 1152 public boolean handleBackKey() { 1153 if (mCurrentSecuritySelection != SecurityMode.None) { 1154 mCallback.dismiss(false); 1155 return true; 1156 } 1157 return false; 1158 } 1159 1160} 1161