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