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