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