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