KeyguardHostView.java revision 105beddcb98efc24f37259881d9b4c267aa0d198
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.keyguard; 18 19import com.android.internal.widget.LockPatternUtils; 20import com.android.keyguard.KeyguardSecurityModel.SecurityMode; 21 22import android.app.Activity; 23import android.app.ActivityManager; 24import android.app.ActivityOptions; 25import android.app.AlertDialog; 26import android.app.SearchManager; 27import android.app.admin.DevicePolicyManager; 28import android.appwidget.AppWidgetHost; 29import android.appwidget.AppWidgetHostView; 30import android.appwidget.AppWidgetManager; 31import android.appwidget.AppWidgetProviderInfo; 32import android.content.ComponentName; 33import android.content.Context; 34import android.content.Intent; 35import android.content.IntentSender; 36import android.content.pm.PackageManager.NameNotFoundException; 37import android.content.pm.UserInfo; 38import android.content.res.Resources; 39import android.graphics.Canvas; 40import android.graphics.Rect; 41import android.os.Looper; 42import android.os.Parcel; 43import android.os.Parcelable; 44import android.os.SystemClock; 45import android.os.UserHandle; 46import android.os.UserManager; 47import android.provider.Settings; 48import android.util.AttributeSet; 49import android.util.Log; 50import android.util.Slog; 51import android.view.KeyEvent; 52import android.view.LayoutInflater; 53import android.view.MotionEvent; 54import android.view.View; 55import android.view.WindowManager; 56import android.view.animation.AnimationUtils; 57import android.widget.RemoteViews.OnClickHandler; 58 59import java.io.File; 60import java.util.List; 61 62public class KeyguardHostView extends KeyguardViewBase { 63 private static final String TAG = "KeyguardHostView"; 64 65 // Use this to debug all of keyguard 66 public static boolean DEBUG = KeyguardViewMediator.DEBUG; 67 68 // Found in KeyguardAppWidgetPickActivity.java 69 static final int APPWIDGET_HOST_ID = 0x4B455947; 70 71 private final int MAX_WIDGETS = 5; 72 73 private AppWidgetHost mAppWidgetHost; 74 private AppWidgetManager mAppWidgetManager; 75 private KeyguardWidgetPager mAppWidgetContainer; 76 private KeyguardSecurityViewFlipper mSecurityViewContainer; 77 private KeyguardSelectorView mKeyguardSelectorView; 78 private KeyguardTransportControlView mTransportControl; 79 private boolean mIsVerifyUnlockOnly; 80 private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView 81 private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; 82 private int mAppWidgetToShow; 83 84 private boolean mCheckAppWidgetConsistencyOnBootCompleted = false; 85 private boolean mCleanupAppWidgetsOnBootCompleted = false; 86 87 protected OnDismissAction mDismissAction; 88 89 protected int mFailedAttempts; 90 private LockPatternUtils mLockPatternUtils; 91 92 private KeyguardSecurityModel mSecurityModel; 93 private KeyguardViewStateManager mViewStateManager; 94 95 private Rect mTempRect = new Rect(); 96 97 private int mDisabledFeatures; 98 99 private boolean mCameraDisabled; 100 101 private boolean mSafeModeEnabled; 102 103 private boolean mUserSetupCompleted; 104 105 // User for whom this host view was created. Final because we should never change the 106 // id without reconstructing an instance of KeyguardHostView. See note below... 107 private final int mUserId; 108 109 private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView; 110 111 /*package*/ interface TransportCallback { 112 void onListenerDetached(); 113 void onListenerAttached(); 114 void onPlayStateChanged(); 115 } 116 117 /*package*/ interface UserSwitcherCallback { 118 void hideSecurityView(int duration); 119 void showSecurityView(); 120 void showUnlockHint(); 121 void userActivity(); 122 } 123 124 /*package*/ interface OnDismissAction { 125 /* returns true if the dismiss should be deferred */ 126 boolean onDismiss(); 127 } 128 129 public KeyguardHostView(Context context) { 130 this(context, null); 131 } 132 133 public KeyguardHostView(Context context, AttributeSet attrs) { 134 super(context, attrs); 135 mLockPatternUtils = new LockPatternUtils(context); 136 137 // Note: This depends on KeyguardHostView getting reconstructed every time the 138 // user switches, since mUserId will be used for the entire session. 139 // Once created, keyguard should *never* re-use this instance with another user. 140 // In other words, mUserId should never change - hence it's marked final. 141 mUserId = mLockPatternUtils.getCurrentUser(); 142 143 DevicePolicyManager dpm = 144 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 145 if (dpm != null) { 146 mDisabledFeatures = getDisabledFeatures(dpm); 147 mCameraDisabled = dpm.getCameraDisabled(null); 148 } 149 150 mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled(); 151 152 // These need to be created with the user context... 153 Context userContext = null; 154 try { 155 final String packageName = "system"; 156 userContext = mContext.createPackageContextAsUser(packageName, 0, 157 new UserHandle(mUserId)); 158 159 } catch (NameNotFoundException e) { 160 e.printStackTrace(); 161 // This should never happen, but it's better to have no widgets than to crash. 162 userContext = context; 163 } 164 165 mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler, 166 Looper.myLooper()); 167 168 cleanupAppWidgetIds(); 169 170 mAppWidgetManager = AppWidgetManager.getInstance(userContext); 171 172 mSecurityModel = new KeyguardSecurityModel(context); 173 174 mViewStateManager = new KeyguardViewStateManager(this); 175 176 mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(), 177 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; 178 179 if (mSafeModeEnabled) { 180 Log.v(TAG, "Keyguard widgets disabled by safe mode"); 181 } 182 if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) { 183 Log.v(TAG, "Keyguard widgets disabled by DPM"); 184 } 185 if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) { 186 Log.v(TAG, "Keyguard secure camera disabled by DPM"); 187 } 188 } 189 190 private void cleanupAppWidgetIds() { 191 // Since this method may delete a widget (which we can't do until boot completed) we 192 // may have to defer it until after boot complete. 193 if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) { 194 mCleanupAppWidgetsOnBootCompleted = true; 195 return; 196 } 197 if (!mSafeModeEnabled && !widgetsDisabledByDpm()) { 198 // Clean up appWidgetIds that are bound to lockscreen, but not actually used 199 // This is only to clean up after another bug: we used to not call 200 // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code 201 // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks 202 // that are triggered by deleteAppWidgetId, which is why we're doing this 203 int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets(); 204 int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds(); 205 for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) { 206 int appWidgetId = appWidgetIdsBoundToHost[i]; 207 if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) { 208 Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id " 209 + appWidgetId); 210 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 211 } 212 } 213 } 214 } 215 216 private static boolean contains(int[] array, int target) { 217 for (int value : array) { 218 if (value == target) { 219 return true; 220 } 221 } 222 return false; 223 } 224 225 private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks = 226 new KeyguardUpdateMonitorCallback() { 227 @Override 228 public void onBootCompleted() { 229 if (mCheckAppWidgetConsistencyOnBootCompleted) { 230 checkAppWidgetConsistency(); 231 mSwitchPageRunnable.run(); 232 mCheckAppWidgetConsistencyOnBootCompleted = false; 233 } 234 if (mCleanupAppWidgetsOnBootCompleted) { 235 cleanupAppWidgetIds(); 236 mCleanupAppWidgetsOnBootCompleted = false; 237 } 238 } 239 @Override 240 public void onUserSwitchComplete(int userId) { 241 if (mKeyguardMultiUserSelectorView != null) { 242 mKeyguardMultiUserSelectorView.finalizeActiveUserView(true); 243 } 244 } 245 }; 246 247 private SlidingChallengeLayout mSlidingChallengeLayout; 248 249 @Override 250 public boolean onTouchEvent(MotionEvent ev) { 251 boolean result = super.onTouchEvent(ev); 252 mTempRect.set(0, 0, 0, 0); 253 offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect); 254 ev.offsetLocation(mTempRect.left, mTempRect.top); 255 result = mSecurityViewContainer.dispatchTouchEvent(ev) || result; 256 ev.offsetLocation(-mTempRect.left, -mTempRect.top); 257 return result; 258 } 259 260 @Override 261 protected void dispatchDraw(Canvas canvas) { 262 super.dispatchDraw(canvas); 263 if (mViewMediatorCallback != null) { 264 mViewMediatorCallback.keyguardDoneDrawing(); 265 } 266 } 267 268 private int getWidgetPosition(int id) { 269 final int children = mAppWidgetContainer.getChildCount(); 270 for (int i = 0; i < children; i++) { 271 if (mAppWidgetContainer.getWidgetPageAt(i).getContent().getId() == id) { 272 return i; 273 } 274 } 275 return -1; 276 } 277 278 @Override 279 protected void onFinishInflate() { 280 // Grab instances of and make any necessary changes to the main layouts. Create 281 // view state manager and wire up necessary listeners / callbacks. 282 View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target); 283 mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container); 284 mAppWidgetContainer.setVisibility(VISIBLE); 285 mAppWidgetContainer.setCallbacks(mWidgetCallbacks); 286 mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget); 287 mAppWidgetContainer.setMinScale(0.5f); 288 289 mSlidingChallengeLayout = (SlidingChallengeLayout) findViewById(R.id.sliding_layout); 290 if (mSlidingChallengeLayout != null) { 291 mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager); 292 } 293 mAppWidgetContainer.setViewStateManager(mViewStateManager); 294 mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils); 295 296 ChallengeLayout challenge = mSlidingChallengeLayout != null ? mSlidingChallengeLayout : 297 (ChallengeLayout) findViewById(R.id.multi_pane_challenge); 298 challenge.setOnBouncerStateChangedListener(mViewStateManager); 299 mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration()); 300 mViewStateManager.setPagedView(mAppWidgetContainer); 301 mViewStateManager.setChallengeLayout(challenge); 302 mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper); 303 mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view); 304 mViewStateManager.setSecurityViewContainer(mSecurityViewContainer); 305 306 if (!(mContext instanceof Activity)) { 307 setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK); 308 } 309 310 addDefaultWidgets(); 311 312 addWidgetsFromSettings(); 313 if (!shouldEnableAddWidget()) { 314 mAppWidgetContainer.setAddWidgetEnabled(false); 315 } 316 checkAppWidgetConsistency(); 317 mSwitchPageRunnable.run(); 318 // This needs to be called after the pages are all added. 319 mViewStateManager.showUsabilityHints(); 320 321 showPrimarySecurityScreen(false); 322 updateSecurityViews(); 323 } 324 325 private boolean shouldEnableAddWidget() { 326 return numWidgets() < MAX_WIDGETS && mUserSetupCompleted; 327 } 328 329 private int getDisabledFeatures(DevicePolicyManager dpm) { 330 int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; 331 if (dpm != null) { 332 final int currentUser = mLockPatternUtils.getCurrentUser(); 333 disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser); 334 } 335 return disabledFeatures; 336 } 337 338 private boolean widgetsDisabledByDpm() { 339 return (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0; 340 } 341 342 private boolean cameraDisabledByDpm() { 343 return mCameraDisabled 344 || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0; 345 } 346 347 private void updateSecurityViews() { 348 int children = mSecurityViewContainer.getChildCount(); 349 for (int i = 0; i < children; i++) { 350 updateSecurityView(mSecurityViewContainer.getChildAt(i)); 351 } 352 } 353 354 private void updateSecurityView(View view) { 355 if (view instanceof KeyguardSecurityView) { 356 KeyguardSecurityView ksv = (KeyguardSecurityView) view; 357 ksv.setKeyguardCallback(mCallback); 358 ksv.setLockPatternUtils(mLockPatternUtils); 359 if (mViewStateManager.isBouncing()) { 360 ksv.showBouncer(0); 361 } else { 362 ksv.hideBouncer(0); 363 } 364 } else { 365 Log.w(TAG, "View " + view + " is not a KeyguardSecurityView"); 366 } 367 } 368 369 void setLockPatternUtils(LockPatternUtils utils) { 370 mSecurityModel.setLockPatternUtils(utils); 371 mLockPatternUtils = utils; 372 updateSecurityViews(); 373 } 374 375 @Override 376 protected void onAttachedToWindow() { 377 super.onAttachedToWindow(); 378 mAppWidgetHost.startListening(); 379 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks); 380 } 381 382 @Override 383 protected void onDetachedFromWindow() { 384 super.onDetachedFromWindow(); 385 mAppWidgetHost.stopListening(); 386 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks); 387 } 388 389 void addWidget(AppWidgetHostView view, int pageIndex) { 390 mAppWidgetContainer.addWidget(view, pageIndex); 391 } 392 393 private KeyguardWidgetPager.Callbacks mWidgetCallbacks 394 = new KeyguardWidgetPager.Callbacks() { 395 @Override 396 public void userActivity() { 397 KeyguardHostView.this.userActivity(); 398 } 399 400 @Override 401 public void onUserActivityTimeoutChanged() { 402 KeyguardHostView.this.onUserActivityTimeoutChanged(); 403 } 404 405 @Override 406 public void onAddView(View v) { 407 if (!shouldEnableAddWidget()) { 408 mAppWidgetContainer.setAddWidgetEnabled(false); 409 } 410 } 411 412 @Override 413 public void onRemoveView(View v, boolean deletePermanently) { 414 if (deletePermanently) { 415 final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); 416 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && 417 appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) { 418 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 419 } 420 } 421 } 422 423 @Override 424 public void onRemoveViewAnimationCompleted() { 425 if (shouldEnableAddWidget()) { 426 mAppWidgetContainer.setAddWidgetEnabled(true); 427 } 428 } 429 }; 430 431 public void initializeSwitchingUserState(boolean switching) { 432 if (!switching && mKeyguardMultiUserSelectorView != null) { 433 mKeyguardMultiUserSelectorView.finalizeActiveUserView(false); 434 } 435 } 436 437 public void userActivity() { 438 if (mViewMediatorCallback != null) { 439 mViewMediatorCallback.userActivity(); 440 } 441 } 442 443 public void onUserActivityTimeoutChanged() { 444 if (mViewMediatorCallback != null) { 445 mViewMediatorCallback.onUserActivityTimeoutChanged(); 446 } 447 } 448 449 @Override 450 public long getUserActivityTimeout() { 451 // Currently only considering user activity timeouts needed by widgets. 452 // Could also take into account longer timeouts for certain security views. 453 if (mAppWidgetContainer != null) { 454 return mAppWidgetContainer.getUserActivityTimeout(); 455 } 456 return -1; 457 } 458 459 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { 460 461 public void userActivity(long timeout) { 462 if (mViewMediatorCallback != null) { 463 mViewMediatorCallback.userActivity(timeout); 464 } 465 } 466 467 public void dismiss(boolean authenticated) { 468 showNextSecurityScreenOrFinish(authenticated); 469 } 470 471 public boolean isVerifyUnlockOnly() { 472 return mIsVerifyUnlockOnly; 473 } 474 475 public void reportSuccessfulUnlockAttempt() { 476 KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts(); 477 mLockPatternUtils.reportSuccessfulPasswordAttempt(); 478 } 479 480 public void reportFailedUnlockAttempt() { 481 if (mCurrentSecuritySelection == SecurityMode.Biometric) { 482 KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt(); 483 } else { 484 KeyguardHostView.this.reportFailedUnlockAttempt(); 485 } 486 } 487 488 public int getFailedAttempts() { 489 return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(); 490 } 491 492 @Override 493 public void showBackupSecurity() { 494 KeyguardHostView.this.showBackupSecurityScreen(); 495 } 496 497 @Override 498 public void setOnDismissAction(OnDismissAction action) { 499 KeyguardHostView.this.setOnDismissAction(action); 500 } 501 502 }; 503 504 private void showDialog(String title, String message) { 505 final AlertDialog dialog = new AlertDialog.Builder(mContext) 506 .setTitle(title) 507 .setMessage(message) 508 .setNeutralButton(R.string.ok, null) 509 .create(); 510 if (!(mContext instanceof Activity)) { 511 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 512 } 513 dialog.show(); 514 } 515 516 private void showTimeoutDialog() { 517 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 518 int messageId = 0; 519 520 switch (mSecurityModel.getSecurityMode()) { 521 case Pattern: 522 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message; 523 break; 524 case PIN: 525 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message; 526 break; 527 case Password: 528 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message; 529 break; 530 } 531 532 if (messageId != 0) { 533 final String message = mContext.getString(messageId, 534 KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(), 535 timeoutInSeconds); 536 showDialog(null, message); 537 } 538 } 539 540 private void showAlmostAtWipeDialog(int attempts, int remaining) { 541 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 542 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe, 543 attempts, remaining); 544 showDialog(null, message); 545 } 546 547 private void showWipeDialog(int attempts) { 548 String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts); 549 showDialog(null, message); 550 } 551 552 private void showAlmostAtAccountLoginDialog() { 553 final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 554 final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 555 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 556 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login, 557 count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); 558 showDialog(null, message); 559 } 560 561 private void reportFailedUnlockAttempt() { 562 final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); 563 final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time 564 565 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); 566 567 SecurityMode mode = mSecurityModel.getSecurityMode(); 568 final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern; 569 570 final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager() 571 .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser()); 572 573 final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 574 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 575 576 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? 577 (failedAttemptsBeforeWipe - failedAttempts) 578 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction 579 580 boolean showTimeout = false; 581 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { 582 // If we reach this code, it means the user has installed a DevicePolicyManager 583 // that requests device wipe after N attempts. Once we get below the grace 584 // period, we'll post this dialog every time as a clear warning until the 585 // bombshell hits and the device is wiped. 586 if (remainingBeforeWipe > 0) { 587 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe); 588 } else { 589 // Too many attempts. The device will be wiped shortly. 590 Slog.i(TAG, "Too many unlock attempts; device will be wiped!"); 591 showWipeDialog(failedAttempts); 592 } 593 } else { 594 showTimeout = 595 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0; 596 if (usingPattern && mEnableFallback) { 597 if (failedAttempts == failedAttemptWarning) { 598 showAlmostAtAccountLoginDialog(); 599 showTimeout = false; // don't show both dialogs 600 } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { 601 mLockPatternUtils.setPermanentlyLocked(true); 602 showSecurityScreen(SecurityMode.Account); 603 // don't show timeout dialog because we show account unlock screen next 604 showTimeout = false; 605 } 606 } 607 } 608 monitor.reportFailedUnlockAttempt(); 609 mLockPatternUtils.reportFailedPasswordAttempt(); 610 if (showTimeout) { 611 showTimeoutDialog(); 612 } 613 } 614 615 /** 616 * Shows the primary security screen for the user. This will be either the multi-selector 617 * or the user's security method. 618 * @param turningOff true if the device is being turned off 619 */ 620 void showPrimarySecurityScreen(boolean turningOff) { 621 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 622 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); 623 if (!turningOff && 624 KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) { 625 // If we're not turning off, then allow biometric alternate. 626 // We'll reload it when the device comes back on. 627 securityMode = mSecurityModel.getAlternateFor(securityMode); 628 } 629 showSecurityScreen(securityMode); 630 } 631 632 /** 633 * Shows the backup security screen for the current security mode. This could be used for 634 * password recovery screens but is currently only used for pattern unlock to show the 635 * account unlock screen and biometric unlock to show the user's normal unlock. 636 */ 637 private void showBackupSecurityScreen() { 638 if (DEBUG) Log.d(TAG, "showBackupSecurity()"); 639 SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection); 640 showSecurityScreen(backup); 641 } 642 643 public boolean showNextSecurityScreenIfPresent() { 644 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 645 // Allow an alternate, such as biometric unlock 646 securityMode = mSecurityModel.getAlternateFor(securityMode); 647 if (SecurityMode.None == securityMode) { 648 return false; 649 } else { 650 showSecurityScreen(securityMode); // switch to the alternate security view 651 return true; 652 } 653 } 654 655 private void showNextSecurityScreenOrFinish(boolean authenticated) { 656 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); 657 boolean finish = false; 658 if (SecurityMode.None == mCurrentSecuritySelection) { 659 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 660 // Allow an alternate, such as biometric unlock 661 securityMode = mSecurityModel.getAlternateFor(securityMode); 662 if (SecurityMode.None == securityMode) { 663 finish = true; // no security required 664 } else { 665 showSecurityScreen(securityMode); // switch to the alternate security view 666 } 667 } else if (authenticated) { 668 switch (mCurrentSecuritySelection) { 669 case Pattern: 670 case Password: 671 case PIN: 672 case Account: 673 case Biometric: 674 finish = true; 675 break; 676 677 case SimPin: 678 case SimPuk: 679 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home 680 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 681 if (securityMode != SecurityMode.None) { 682 showSecurityScreen(securityMode); 683 } else { 684 finish = true; 685 } 686 break; 687 688 default: 689 Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe"); 690 showPrimarySecurityScreen(false); 691 break; 692 } 693 } else { 694 showPrimarySecurityScreen(false); 695 } 696 if (finish) { 697 // If the alternate unlock was suppressed, it can now be safely 698 // enabled because the user has left keyguard. 699 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); 700 701 // If there's a pending runnable because the user interacted with a widget 702 // and we're leaving keyguard, then run it. 703 boolean deferKeyguardDone = false; 704 if (mDismissAction != null) { 705 deferKeyguardDone = mDismissAction.onDismiss(); 706 mDismissAction = null; 707 } 708 if (mViewMediatorCallback != null) { 709 if (deferKeyguardDone) { 710 mViewMediatorCallback.keyguardDonePending(); 711 } else { 712 mViewMediatorCallback.keyguardDone(true); 713 } 714 } 715 } else { 716 mViewStateManager.showBouncer(true); 717 } 718 } 719 720 private OnClickHandler mOnClickHandler = new OnClickHandler() { 721 @Override 722 public boolean onClickHandler(final View view, 723 final android.app.PendingIntent pendingIntent, 724 final Intent fillInIntent) { 725 if (pendingIntent.isActivity()) { 726 setOnDismissAction(new OnDismissAction() { 727 public boolean onDismiss() { 728 try { 729 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? 730 Context context = view.getContext(); 731 ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, 732 0, 0, 733 view.getMeasuredWidth(), view.getMeasuredHeight()); 734 context.startIntentSender( 735 pendingIntent.getIntentSender(), fillInIntent, 736 Intent.FLAG_ACTIVITY_NEW_TASK, 737 Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle()); 738 } catch (IntentSender.SendIntentException e) { 739 android.util.Log.e(TAG, "Cannot send pending intent: ", e); 740 } catch (Exception e) { 741 android.util.Log.e(TAG, "Cannot send pending intent due to " + 742 "unknown exception: ", e); 743 } 744 return false; 745 } 746 }); 747 748 if (mViewStateManager.isChallengeShowing()) { 749 mViewStateManager.showBouncer(true); 750 } else { 751 mCallback.dismiss(false); 752 } 753 return true; 754 } else { 755 return super.onClickHandler(view, pendingIntent, fillInIntent); 756 } 757 }; 758 }; 759 760 // Used to ignore callbacks from methods that are no longer current (e.g. face unlock). 761 // This avoids unwanted asynchronous events from messing with the state. 762 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { 763 764 @Override 765 public void userActivity(long timeout) { 766 } 767 768 @Override 769 public void showBackupSecurity() { 770 } 771 772 @Override 773 public void setOnDismissAction(OnDismissAction action) { 774 } 775 776 @Override 777 public void reportSuccessfulUnlockAttempt() { 778 } 779 780 @Override 781 public void reportFailedUnlockAttempt() { 782 } 783 784 @Override 785 public boolean isVerifyUnlockOnly() { 786 return false; 787 } 788 789 @Override 790 public int getFailedAttempts() { 791 return 0; 792 } 793 794 @Override 795 public void dismiss(boolean securityVerified) { 796 } 797 }; 798 799 protected boolean mShowSecurityWhenReturn; 800 801 @Override 802 public void reset() { 803 mIsVerifyUnlockOnly = false; 804 mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_status_view)); 805 } 806 807 /** 808 * Sets an action to perform when keyguard is dismissed. 809 * @param action 810 */ 811 protected void setOnDismissAction(OnDismissAction action) { 812 mDismissAction = action; 813 } 814 815 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { 816 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 817 KeyguardSecurityView view = null; 818 final int children = mSecurityViewContainer.getChildCount(); 819 for (int child = 0; child < children; child++) { 820 if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) { 821 view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child)); 822 break; 823 } 824 } 825 int layoutId = getLayoutIdFor(securityMode); 826 if (view == null && layoutId != 0) { 827 final LayoutInflater inflater = LayoutInflater.from(mContext); 828 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); 829 View v = inflater.inflate(layoutId, mSecurityViewContainer, false); 830 mSecurityViewContainer.addView(v); 831 updateSecurityView(v); 832 view = (KeyguardSecurityView)v; 833 } 834 835 if (view instanceof KeyguardSelectorView) { 836 KeyguardSelectorView selectorView = (KeyguardSelectorView) view; 837 View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container); 838 selectorView.setCarrierArea(carrierText); 839 } 840 841 return view; 842 } 843 844 /** 845 * Switches to the given security view unless it's already being shown, in which case 846 * this is a no-op. 847 * 848 * @param securityMode 849 */ 850 private void showSecurityScreen(SecurityMode securityMode) { 851 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); 852 853 if (securityMode == mCurrentSecuritySelection) return; 854 855 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); 856 KeyguardSecurityView newView = getSecurityView(securityMode); 857 858 // Enter full screen mode if we're in SIM or Account screen 859 boolean fullScreenEnabled = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen); 860 boolean isSimOrAccount = securityMode == SecurityMode.SimPin 861 || securityMode == SecurityMode.SimPuk 862 || securityMode == SecurityMode.Account; 863 mAppWidgetContainer.setVisibility( 864 isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE); 865 866 if (mSlidingChallengeLayout != null) { 867 mSlidingChallengeLayout.setChallengeInteractive(!fullScreenEnabled); 868 } 869 870 // Emulate Activity life cycle 871 if (oldView != null) { 872 oldView.onPause(); 873 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view 874 } 875 newView.onResume(KeyguardSecurityView.VIEW_REVEALED); 876 newView.setKeyguardCallback(mCallback); 877 878 final boolean needsInput = newView.needsInput(); 879 if (mViewMediatorCallback != null) { 880 mViewMediatorCallback.setNeedsInput(needsInput); 881 } 882 883 // Find and show this child. 884 final int childCount = mSecurityViewContainer.getChildCount(); 885 886 mSecurityViewContainer.setInAnimation( 887 AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in)); 888 mSecurityViewContainer.setOutAnimation( 889 AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out)); 890 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 891 for (int i = 0; i < childCount; i++) { 892 if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) { 893 mSecurityViewContainer.setDisplayedChild(i); 894 break; 895 } 896 } 897 898 if (securityMode == SecurityMode.None) { 899 // Discard current runnable if we're switching back to the selector view 900 setOnDismissAction(null); 901 } 902 mCurrentSecuritySelection = securityMode; 903 } 904 905 @Override 906 public void onScreenTurnedOn() { 907 if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); 908 showPrimarySecurityScreen(false); 909 getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON); 910 911 // This is a an attempt to fix bug 7137389 where the device comes back on but the entire 912 // layout is blank but forcing a layout causes it to reappear (e.g. with with 913 // hierarchyviewer). 914 requestLayout(); 915 916 if (mViewStateManager != null) { 917 mViewStateManager.showUsabilityHints(); 918 } 919 requestFocus(); 920 } 921 922 @Override 923 public void onScreenTurnedOff() { 924 if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s", 925 Integer.toHexString(hashCode()), SystemClock.uptimeMillis())); 926 // Once the screen turns off, we no longer consider this to be first boot and we want the 927 // biometric unlock to start next time keyguard is shown. 928 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); 929 // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen 930 // turns off we reset that behavior 931 clearAppWidgetToShow(); 932 checkAppWidgetConsistency(); 933 showPrimarySecurityScreen(true); 934 getSecurityView(mCurrentSecuritySelection).onPause(); 935 CameraWidgetFrame cameraPage = findCameraPage(); 936 if (cameraPage != null) { 937 cameraPage.onScreenTurnedOff(); 938 } 939 clearFocus(); 940 } 941 942 public void clearAppWidgetToShow() { 943 mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID; 944 } 945 946 @Override 947 public void show() { 948 if (DEBUG) Log.d(TAG, "show()"); 949 showPrimarySecurityScreen(false); 950 } 951 952 private boolean isSecure() { 953 SecurityMode mode = mSecurityModel.getSecurityMode(); 954 switch (mode) { 955 case Pattern: 956 return mLockPatternUtils.isLockPatternEnabled(); 957 case Password: 958 case PIN: 959 return mLockPatternUtils.isLockPasswordEnabled(); 960 case SimPin: 961 case SimPuk: 962 case Account: 963 return true; 964 case None: 965 return false; 966 default: 967 throw new IllegalStateException("Unknown security mode " + mode); 968 } 969 } 970 971 @Override 972 public void wakeWhenReadyTq(int keyCode) { 973 if (DEBUG) Log.d(TAG, "onWakeKey"); 974 if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) { 975 if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); 976 showSecurityScreen(SecurityMode.None); 977 } else { 978 if (DEBUG) Log.d(TAG, "poking wake lock immediately"); 979 } 980 if (mViewMediatorCallback != null) { 981 mViewMediatorCallback.wakeUp(); 982 } 983 } 984 985 @Override 986 public void verifyUnlock() { 987 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 988 if (securityMode == KeyguardSecurityModel.SecurityMode.None) { 989 if (mViewMediatorCallback != null) { 990 mViewMediatorCallback.keyguardDone(true); 991 } 992 } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern 993 && securityMode != KeyguardSecurityModel.SecurityMode.PIN 994 && securityMode != KeyguardSecurityModel.SecurityMode.Password) { 995 // can only verify unlock when in pattern/password mode 996 if (mViewMediatorCallback != null) { 997 mViewMediatorCallback.keyguardDone(false); 998 } 999 } else { 1000 // otherwise, go to the unlock screen, see if they can verify it 1001 mIsVerifyUnlockOnly = true; 1002 showSecurityScreen(securityMode); 1003 } 1004 } 1005 1006 private int getSecurityViewIdForMode(SecurityMode securityMode) { 1007 switch (securityMode) { 1008 case None: return R.id.keyguard_selector_view; 1009 case Pattern: return R.id.keyguard_pattern_view; 1010 case PIN: return R.id.keyguard_pin_view; 1011 case Password: return R.id.keyguard_password_view; 1012 case Biometric: return R.id.keyguard_face_unlock_view; 1013 case Account: return R.id.keyguard_account_view; 1014 case SimPin: return R.id.keyguard_sim_pin_view; 1015 case SimPuk: return R.id.keyguard_sim_puk_view; 1016 } 1017 return 0; 1018 } 1019 1020 private int getLayoutIdFor(SecurityMode securityMode) { 1021 switch (securityMode) { 1022 case None: return R.layout.keyguard_selector_view; 1023 case Pattern: return R.layout.keyguard_pattern_view; 1024 case PIN: return R.layout.keyguard_pin_view; 1025 case Password: return R.layout.keyguard_password_view; 1026 case Biometric: return R.layout.keyguard_face_unlock_view; 1027 case Account: return R.layout.keyguard_account_view; 1028 case SimPin: return R.layout.keyguard_sim_pin_view; 1029 case SimPuk: return R.layout.keyguard_sim_puk_view; 1030 default: 1031 return 0; 1032 } 1033 } 1034 1035 private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) { 1036 AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId); 1037 if (appWidgetInfo != null) { 1038 AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo); 1039 addWidget(view, pageIndex); 1040 return true; 1041 } else { 1042 if (updateDbIfFailed) { 1043 Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + " was null for user" 1044 + mUserId + ", deleting"); 1045 mAppWidgetHost.deleteAppWidgetId(appId); 1046 mLockPatternUtils.removeAppWidget(appId); 1047 } 1048 return false; 1049 } 1050 } 1051 1052 private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks = 1053 new CameraWidgetFrame.Callbacks() { 1054 @Override 1055 public void onLaunchingCamera() { 1056 setSliderHandleAlpha(0); 1057 } 1058 1059 @Override 1060 public void onCameraLaunchedSuccessfully() { 1061 if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) { 1062 mAppWidgetContainer.scrollLeft(); 1063 } 1064 setSliderHandleAlpha(1); 1065 mShowSecurityWhenReturn = true; 1066 } 1067 1068 @Override 1069 public void onCameraLaunchedUnsuccessfully() { 1070 setSliderHandleAlpha(1); 1071 } 1072 1073 private void setSliderHandleAlpha(float alpha) { 1074 SlidingChallengeLayout slider = 1075 (SlidingChallengeLayout) findViewById(R.id.sliding_layout); 1076 if (slider != null) { 1077 slider.setHandleAlpha(alpha); 1078 } 1079 } 1080 }; 1081 1082 private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { 1083 @Override 1084 Context getContext() { 1085 return mContext; 1086 } 1087 1088 @Override 1089 KeyguardSecurityCallback getCallback() { 1090 return mCallback; 1091 } 1092 1093 @Override 1094 LockPatternUtils getLockPatternUtils() { 1095 return mLockPatternUtils; 1096 } 1097 }; 1098 1099 private int numWidgets() { 1100 final int childCount = mAppWidgetContainer.getChildCount(); 1101 int widgetCount = 0; 1102 for (int i = 0; i < childCount; i++) { 1103 if (mAppWidgetContainer.isWidgetPage(i)) { 1104 widgetCount++; 1105 } 1106 } 1107 return widgetCount; 1108 } 1109 1110 private void addDefaultWidgets() { 1111 LayoutInflater inflater = LayoutInflater.from(mContext); 1112 inflater.inflate(R.layout.keyguard_transport_control_view, this, true); 1113 1114 if (!mSafeModeEnabled && !widgetsDisabledByDpm()) { 1115 View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false); 1116 mAppWidgetContainer.addWidget(addWidget, 0); 1117 View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view); 1118 addWidgetButton.setOnClickListener(new OnClickListener() { 1119 @Override 1120 public void onClick(View v) { 1121 // Pass in an invalid widget id... the picker will allocate an ID for us 1122 mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID); 1123 } 1124 }); 1125 } 1126 1127 // We currently disable cameras in safe mode because we support loading 3rd party 1128 // cameras we can't trust. TODO: plumb safe mode into camera creation code and only 1129 // inflate system-provided camera? 1130 if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted 1131 && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) { 1132 View cameraWidget = 1133 CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher); 1134 if (cameraWidget != null) { 1135 mAppWidgetContainer.addWidget(cameraWidget); 1136 } 1137 } 1138 1139 enableUserSelectorIfNecessary(); 1140 initializeTransportControl(); 1141 } 1142 1143 private boolean removeTransportFromWidgetPager() { 1144 int page = getWidgetPosition(R.id.keyguard_transport_control); 1145 if (page != -1) { 1146 mAppWidgetContainer.removeWidget(mTransportControl); 1147 1148 // XXX keep view attached so we still get show/hide events from AudioManager 1149 KeyguardHostView.this.addView(mTransportControl); 1150 mTransportControl.setVisibility(View.GONE); 1151 mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE); 1152 return true; 1153 } 1154 return false; 1155 } 1156 1157 private void addTransportToWidgetPager() { 1158 if (getWidgetPosition(R.id.keyguard_transport_control) == -1) { 1159 KeyguardHostView.this.removeView(mTransportControl); 1160 // insert to left of camera if it exists, otherwise after right-most widget 1161 int lastWidget = mAppWidgetContainer.getChildCount() - 1; 1162 int position = 0; // handle no widget case 1163 if (lastWidget >= 0) { 1164 position = mAppWidgetContainer.isCameraPage(lastWidget) ? 1165 lastWidget : lastWidget + 1; 1166 } 1167 mAppWidgetContainer.addWidget(mTransportControl, position); 1168 mTransportControl.setVisibility(View.VISIBLE); 1169 } 1170 } 1171 1172 private void initializeTransportControl() { 1173 mTransportControl = 1174 (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control); 1175 mTransportControl.setVisibility(View.GONE); 1176 1177 // This code manages showing/hiding the transport control. We keep it around and only 1178 // add it to the hierarchy if it needs to be present. 1179 if (mTransportControl != null) { 1180 mTransportControl.setKeyguardCallback(new TransportCallback() { 1181 @Override 1182 public void onListenerDetached() { 1183 if (removeTransportFromWidgetPager()) { 1184 mTransportControl.post(mSwitchPageRunnable); 1185 } 1186 } 1187 1188 @Override 1189 public void onListenerAttached() { 1190 // Transport will be added when playstate changes... 1191 mTransportControl.post(mSwitchPageRunnable); 1192 } 1193 1194 @Override 1195 public void onPlayStateChanged() { 1196 mTransportControl.post(mSwitchPageRunnable); 1197 } 1198 }); 1199 } 1200 } 1201 1202 private int getInsertPageIndex() { 1203 View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget); 1204 int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget); 1205 if (insertionIndex < 0) { 1206 insertionIndex = 0; // no add widget page found 1207 } else { 1208 insertionIndex++; // place after add widget 1209 } 1210 return insertionIndex; 1211 } 1212 1213 private void addDefaultStatusWidget(int index) { 1214 LayoutInflater inflater = LayoutInflater.from(mContext); 1215 View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true); 1216 mAppWidgetContainer.addWidget(statusWidget, index); 1217 } 1218 1219 private void addWidgetsFromSettings() { 1220 if (mSafeModeEnabled || widgetsDisabledByDpm()) { 1221 return; 1222 } 1223 1224 int insertionIndex = getInsertPageIndex(); 1225 1226 // Add user-selected widget 1227 final int[] widgets = mLockPatternUtils.getAppWidgets(); 1228 1229 if (widgets == null) { 1230 Log.d(TAG, "Problem reading widgets"); 1231 } else { 1232 for (int i = widgets.length -1; i >= 0; i--) { 1233 if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) { 1234 addDefaultStatusWidget(insertionIndex); 1235 } else { 1236 // We add the widgets from left to right, starting after the first page after 1237 // the add page. We count down, since the order will be persisted from right 1238 // to left, starting after camera. 1239 addWidget(widgets[i], insertionIndex, true); 1240 } 1241 } 1242 } 1243 } 1244 1245 private int allocateIdForDefaultAppWidget() { 1246 int appWidgetId; 1247 Resources res = getContext().getResources(); 1248 ComponentName defaultAppWidget = new ComponentName( 1249 res.getString(R.string.widget_default_package_name), 1250 res.getString(R.string.widget_default_class_name)); 1251 1252 // Note: we don't support configuring the widget 1253 appWidgetId = mAppWidgetHost.allocateAppWidgetId(); 1254 1255 try { 1256 mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget); 1257 1258 } catch (IllegalArgumentException e) { 1259 Log.e(TAG, "Error when trying to bind default AppWidget: " + e); 1260 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 1261 appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; 1262 } 1263 return appWidgetId; 1264 } 1265 public void checkAppWidgetConsistency() { 1266 // Since this method may bind a widget (which we can't do until boot completed) we 1267 // may have to defer it until after boot complete. 1268 if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) { 1269 mCheckAppWidgetConsistencyOnBootCompleted = true; 1270 return; 1271 } 1272 final int childCount = mAppWidgetContainer.getChildCount(); 1273 boolean widgetPageExists = false; 1274 for (int i = 0; i < childCount; i++) { 1275 if (mAppWidgetContainer.isWidgetPage(i)) { 1276 widgetPageExists = true; 1277 break; 1278 } 1279 } 1280 if (!widgetPageExists) { 1281 final int insertPageIndex = getInsertPageIndex(); 1282 1283 final boolean userAddedWidgetsEnabled = !widgetsDisabledByDpm(); 1284 boolean addedDefaultAppWidget = false; 1285 1286 if (!mSafeModeEnabled) { 1287 if (userAddedWidgetsEnabled) { 1288 int appWidgetId = allocateIdForDefaultAppWidget(); 1289 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 1290 addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true); 1291 } 1292 } else { 1293 // note: even if widgetsDisabledByDpm() returns true, we still bind/create 1294 // the default appwidget if possible 1295 int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId(); 1296 if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { 1297 appWidgetId = allocateIdForDefaultAppWidget(); 1298 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 1299 mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId); 1300 } 1301 } 1302 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 1303 addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false); 1304 if (!addedDefaultAppWidget) { 1305 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 1306 mLockPatternUtils.writeFallbackAppWidgetId( 1307 AppWidgetManager.INVALID_APPWIDGET_ID); 1308 } 1309 } 1310 } 1311 } 1312 1313 // Use the built-in status/clock view if we can't inflate the default widget 1314 if (!addedDefaultAppWidget) { 1315 addDefaultStatusWidget(insertPageIndex); 1316 } 1317 1318 // trigger DB updates only if user-added widgets are enabled 1319 if (!mSafeModeEnabled && userAddedWidgetsEnabled) { 1320 mAppWidgetContainer.onAddView( 1321 mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex); 1322 } 1323 } 1324 } 1325 1326 Runnable mSwitchPageRunnable = new Runnable() { 1327 @Override 1328 public void run() { 1329 showAppropriateWidgetPage(); 1330 } 1331 }; 1332 1333 static class SavedState extends BaseSavedState { 1334 int transportState; 1335 int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID; 1336 1337 SavedState(Parcelable superState) { 1338 super(superState); 1339 } 1340 1341 private SavedState(Parcel in) { 1342 super(in); 1343 this.transportState = in.readInt(); 1344 this.appWidgetToShow = in.readInt(); 1345 } 1346 1347 @Override 1348 public void writeToParcel(Parcel out, int flags) { 1349 super.writeToParcel(out, flags); 1350 out.writeInt(this.transportState); 1351 out.writeInt(this.appWidgetToShow); 1352 } 1353 1354 public static final Parcelable.Creator<SavedState> CREATOR 1355 = new Parcelable.Creator<SavedState>() { 1356 public SavedState createFromParcel(Parcel in) { 1357 return new SavedState(in); 1358 } 1359 1360 public SavedState[] newArray(int size) { 1361 return new SavedState[size]; 1362 } 1363 }; 1364 } 1365 1366 @Override 1367 public Parcelable onSaveInstanceState() { 1368 if (DEBUG) Log.d(TAG, "onSaveInstanceState"); 1369 Parcelable superState = super.onSaveInstanceState(); 1370 SavedState ss = new SavedState(superState); 1371 ss.transportState = mViewStateManager.getTransportState(); 1372 ss.appWidgetToShow = mAppWidgetToShow; 1373 return ss; 1374 } 1375 1376 @Override 1377 public void onRestoreInstanceState(Parcelable state) { 1378 if (DEBUG) Log.d(TAG, "onRestoreInstanceState"); 1379 if (!(state instanceof SavedState)) { 1380 super.onRestoreInstanceState(state); 1381 return; 1382 } 1383 SavedState ss = (SavedState) state; 1384 super.onRestoreInstanceState(ss.getSuperState()); 1385 mViewStateManager.setTransportState(ss.transportState); 1386 mAppWidgetToShow = ss.appWidgetToShow; 1387 post(mSwitchPageRunnable); 1388 } 1389 1390 @Override 1391 public void onWindowFocusChanged(boolean hasWindowFocus) { 1392 super.onWindowFocusChanged(hasWindowFocus); 1393 if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused")); 1394 if (hasWindowFocus && mShowSecurityWhenReturn) { 1395 SlidingChallengeLayout slider = 1396 (SlidingChallengeLayout) findViewById(R.id.sliding_layout); 1397 if (slider != null) { 1398 slider.setHandleAlpha(1); 1399 slider.showChallenge(true); 1400 } 1401 mShowSecurityWhenReturn = false; 1402 } 1403 } 1404 1405 private void showAppropriateWidgetPage() { 1406 int state = mViewStateManager.getTransportState(); 1407 boolean isMusicPlaying = mTransportControl.isMusicPlaying() 1408 || state == KeyguardViewStateManager.TRANSPORT_VISIBLE; 1409 if (isMusicPlaying) { 1410 mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE); 1411 addTransportToWidgetPager(); 1412 } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) { 1413 mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE); 1414 } 1415 int pageToShow = getAppropriateWidgetPage(isMusicPlaying); 1416 mAppWidgetContainer.setCurrentPage(pageToShow); 1417 } 1418 1419 private CameraWidgetFrame findCameraPage() { 1420 for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) { 1421 if (mAppWidgetContainer.isCameraPage(i)) { 1422 return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i); 1423 } 1424 } 1425 return null; 1426 } 1427 1428 boolean isMusicPage(int pageIndex) { 1429 return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control); 1430 } 1431 1432 private int getAppropriateWidgetPage(boolean isMusicPlaying) { 1433 // assumes at least one widget (besides camera + add) 1434 if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) { 1435 final int childCount = mAppWidgetContainer.getChildCount(); 1436 for (int i = 0; i < childCount; i++) { 1437 if (mAppWidgetContainer.getWidgetPageAt(i).getContentAppWidgetId() 1438 == mAppWidgetToShow) { 1439 return i; 1440 } 1441 } 1442 mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID; 1443 } 1444 // if music playing, show transport 1445 if (isMusicPlaying) { 1446 if (DEBUG) Log.d(TAG, "Music playing, show transport"); 1447 return mAppWidgetContainer.getWidgetPageIndex(mTransportControl); 1448 } 1449 1450 // else show the right-most widget (except for camera) 1451 int rightMost = mAppWidgetContainer.getChildCount() - 1; 1452 if (mAppWidgetContainer.isCameraPage(rightMost)) { 1453 rightMost--; 1454 } 1455 if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost); 1456 return rightMost; 1457 } 1458 1459 private void enableUserSelectorIfNecessary() { 1460 if (!UserManager.supportsMultipleUsers()) { 1461 return; // device doesn't support multi-user mode 1462 } 1463 final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1464 if (um == null) { 1465 Throwable t = new Throwable(); 1466 t.fillInStackTrace(); 1467 Log.e(TAG, "user service is null.", t); 1468 return; 1469 } 1470 1471 // if there are multiple users, we need to enable to multi-user switcher 1472 final List<UserInfo> users = um.getUsers(true); 1473 if (users == null) { 1474 Throwable t = new Throwable(); 1475 t.fillInStackTrace(); 1476 Log.e(TAG, "list of users is null.", t); 1477 return; 1478 } 1479 1480 final View multiUserView = findViewById(R.id.keyguard_user_selector); 1481 if (multiUserView == null) { 1482 Throwable t = new Throwable(); 1483 t.fillInStackTrace(); 1484 Log.e(TAG, "can't find user_selector in layout.", t); 1485 return; 1486 } 1487 1488 if (users.size() > 1) { 1489 if (multiUserView instanceof KeyguardMultiUserSelectorView) { 1490 mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView; 1491 mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE); 1492 mKeyguardMultiUserSelectorView.addUsers(users); 1493 UserSwitcherCallback callback = new UserSwitcherCallback() { 1494 @Override 1495 public void hideSecurityView(int duration) { 1496 mSecurityViewContainer.animate().alpha(0).setDuration(duration); 1497 } 1498 1499 @Override 1500 public void showSecurityView() { 1501 mSecurityViewContainer.setAlpha(1.0f); 1502 } 1503 1504 @Override 1505 public void showUnlockHint() { 1506 if (mKeyguardSelectorView != null) { 1507 mKeyguardSelectorView.showUsabilityHint(); 1508 } 1509 } 1510 1511 @Override 1512 public void userActivity() { 1513 if (mViewMediatorCallback != null) { 1514 mViewMediatorCallback.userActivity(); 1515 } 1516 } 1517 }; 1518 mKeyguardMultiUserSelectorView.setCallback(callback); 1519 } else { 1520 Throwable t = new Throwable(); 1521 t.fillInStackTrace(); 1522 if (multiUserView == null) { 1523 Log.e(TAG, "could not find the user_selector.", t); 1524 } else { 1525 Log.e(TAG, "user_selector is the wrong type.", t); 1526 } 1527 } 1528 } 1529 } 1530 1531 @Override 1532 public void cleanUp() { 1533 1534 } 1535 1536 /** 1537 * In general, we enable unlocking the insecure keyguard with the menu key. However, there are 1538 * some cases where we wish to disable it, notably when the menu button placement or technology 1539 * is prone to false positives. 1540 * 1541 * @return true if the menu key should be enabled 1542 */ 1543 private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; 1544 private boolean shouldEnableMenuKey() { 1545 final Resources res = getResources(); 1546 final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); 1547 final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); 1548 final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); 1549 return !configDisabled || isTestHarness || fileOverride; 1550 } 1551 1552 public void goToWidget(int appWidgetId) { 1553 mAppWidgetToShow = appWidgetId; 1554 mSwitchPageRunnable.run(); 1555 } 1556 1557 public boolean handleMenuKey() { 1558 // The following enables the MENU key to work for testing automation 1559 if (shouldEnableMenuKey()) { 1560 showNextSecurityScreenOrFinish(false); 1561 return true; 1562 } 1563 return false; 1564 } 1565 1566 public boolean handleBackKey() { 1567 if (mCurrentSecuritySelection != SecurityMode.None) { 1568 mCallback.dismiss(false); 1569 return true; 1570 } 1571 return false; 1572 } 1573 1574 /** 1575 * Dismisses the keyguard by going to the next screen or making it gone. 1576 */ 1577 public void dismiss() { 1578 showNextSecurityScreenOrFinish(false); 1579 } 1580 1581 public void showAssistant() { 1582 final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) 1583 .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); 1584 1585 if (intent == null) return; 1586 1587 final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 1588 R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit, 1589 getHandler(), null); 1590 1591 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1592 1593 mActivityLauncher.launchActivityWithAnimation( 1594 intent, false, opts.toBundle(), null, null); 1595 } 1596} 1597