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