KeyguardHostView.java revision efb3ffb029efcc180b3233b6f25d2dba11e28f03
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.SystemProperties; 41import android.os.UserHandle; 42import android.os.UserManager; 43import android.util.AttributeSet; 44import android.util.Log; 45import android.util.Slog; 46import android.view.KeyEvent; 47import android.view.LayoutInflater; 48import android.view.MotionEvent; 49import android.view.View; 50import android.view.WindowManager; 51import android.view.animation.AnimationUtils; 52import android.widget.RemoteViews.OnClickHandler; 53 54import com.android.internal.R; 55import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode; 56import com.android.internal.widget.LockPatternUtils; 57 58import java.io.File; 59import java.util.List; 60 61public class KeyguardHostView extends KeyguardViewBase { 62 private static final String TAG = "KeyguardHostView"; 63 64 // Use this to debug all of keyguard 65 public static boolean DEBUG = KeyguardViewMediator.DEBUG; 66 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 79 private boolean mBootCompleted = false; 80 private boolean mCheckAppWidgetConsistencyOnBootCompleted = false; 81 82 protected Runnable mLaunchRunnable; 83 84 protected int mFailedAttempts; 85 private LockPatternUtils mLockPatternUtils; 86 87 private KeyguardSecurityModel mSecurityModel; 88 private KeyguardViewStateManager mViewStateManager; 89 90 int mLocalStickyWidget = -1; 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 setOnDismissRunnable(Runnable runnable) { 369 KeyguardHostView.this.setOnDismissRunnable(runnable); 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 if (mLaunchRunnable != null) { 574 mLaunchRunnable.run(); 575 mLaunchRunnable = null; 576 } 577 if (mViewMediatorCallback != null) { 578 mViewMediatorCallback.keyguardDone(true); 579 } 580 } else { 581 mViewStateManager.showBouncer(true); 582 } 583 } 584 585 private OnClickHandler mOnClickHandler = new OnClickHandler() { 586 @Override 587 public boolean onClickHandler(final View view, 588 final android.app.PendingIntent pendingIntent, 589 final Intent fillInIntent) { 590 if (pendingIntent.isActivity()) { 591 setOnDismissRunnable(new Runnable() { 592 public void run() { 593 try { 594 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? 595 Context context = view.getContext(); 596 ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, 597 0, 0, 598 view.getMeasuredWidth(), view.getMeasuredHeight()); 599 context.startIntentSender( 600 pendingIntent.getIntentSender(), fillInIntent, 601 Intent.FLAG_ACTIVITY_NEW_TASK, 602 Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle()); 603 } catch (IntentSender.SendIntentException e) { 604 android.util.Log.e(TAG, "Cannot send pending intent: ", e); 605 } catch (Exception e) { 606 android.util.Log.e(TAG, "Cannot send pending intent due to " + 607 "unknown exception: ", e); 608 } 609 } 610 }); 611 612 if (mViewStateManager.isChallengeShowing()) { 613 mViewStateManager.showBouncer(true); 614 } else { 615 mCallback.dismiss(false); 616 } 617 return true; 618 } else { 619 return super.onClickHandler(view, pendingIntent, fillInIntent); 620 } 621 }; 622 }; 623 624 // Used to ignore callbacks from methods that are no longer current (e.g. face unlock). 625 // This avoids unwanted asynchronous events from messing with the state. 626 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { 627 628 @Override 629 public void userActivity(long timeout) { 630 } 631 632 @Override 633 public void showBackupSecurity() { 634 } 635 636 @Override 637 public void setOnDismissRunnable(Runnable runnable) { 638 } 639 640 @Override 641 public void reportSuccessfulUnlockAttempt() { 642 } 643 644 @Override 645 public void reportFailedUnlockAttempt() { 646 } 647 648 @Override 649 public boolean isVerifyUnlockOnly() { 650 return false; 651 } 652 653 @Override 654 public int getFailedAttempts() { 655 return 0; 656 } 657 658 @Override 659 public void dismiss(boolean securityVerified) { 660 } 661 }; 662 663 protected boolean mShowSecurityWhenReturn; 664 665 @Override 666 public void reset() { 667 mIsVerifyUnlockOnly = false; 668 mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_status_view)); 669 } 670 671 /** 672 * Sets a runnable to run when keyguard is dismissed 673 * @param runnable 674 */ 675 protected void setOnDismissRunnable(Runnable runnable) { 676 mLaunchRunnable = runnable; 677 } 678 679 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { 680 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 681 KeyguardSecurityView view = null; 682 final int children = mSecurityViewContainer.getChildCount(); 683 for (int child = 0; child < children; child++) { 684 if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) { 685 view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child)); 686 break; 687 } 688 } 689 int layoutId = getLayoutIdFor(securityMode); 690 if (view == null && layoutId != 0) { 691 final LayoutInflater inflater = LayoutInflater.from(mContext); 692 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); 693 View v = inflater.inflate(layoutId, this, false); 694 mSecurityViewContainer.addView(v); 695 updateSecurityView(v); 696 view = (KeyguardSecurityView)v; 697 } 698 699 if (view instanceof KeyguardSelectorView) { 700 KeyguardSelectorView selectorView = (KeyguardSelectorView) view; 701 View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container); 702 selectorView.setCarrierArea(carrierText); 703 } 704 705 return view; 706 } 707 708 /** 709 * Switches to the given security view unless it's already being shown, in which case 710 * this is a no-op. 711 * 712 * @param securityMode 713 */ 714 private void showSecurityScreen(SecurityMode securityMode) { 715 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); 716 717 if (securityMode == mCurrentSecuritySelection) return; 718 719 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); 720 KeyguardSecurityView newView = getSecurityView(securityMode); 721 722 // Enter full screen mode if we're in SIM or Account screen 723 boolean fullScreenEnabled = getResources().getBoolean( 724 com.android.internal.R.bool.kg_sim_puk_account_full_screen); 725 boolean isSimOrAccount = securityMode == SecurityMode.SimPin 726 || securityMode == SecurityMode.SimPuk 727 || securityMode == SecurityMode.Account; 728 mAppWidgetContainer.setVisibility( 729 isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE); 730 731 // Emulate Activity life cycle 732 if (oldView != null) { 733 oldView.onPause(); 734 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view 735 } 736 newView.onResume(); 737 newView.setKeyguardCallback(mCallback); 738 739 final boolean needsInput = newView.needsInput(); 740 if (mViewMediatorCallback != null) { 741 mViewMediatorCallback.setNeedsInput(needsInput); 742 } 743 744 // Find and show this child. 745 final int childCount = mSecurityViewContainer.getChildCount(); 746 747 mSecurityViewContainer.setInAnimation( 748 AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in)); 749 mSecurityViewContainer.setOutAnimation( 750 AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out)); 751 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); 752 for (int i = 0; i < childCount; i++) { 753 if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) { 754 mSecurityViewContainer.setDisplayedChild(i); 755 break; 756 } 757 } 758 759 if (securityMode == SecurityMode.None) { 760 // Discard current runnable if we're switching back to the selector view 761 setOnDismissRunnable(null); 762 } 763 mCurrentSecuritySelection = securityMode; 764 } 765 766 @Override 767 public void onScreenTurnedOn() { 768 if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); 769 showPrimarySecurityScreen(false); 770 getSecurityView(mCurrentSecuritySelection).onResume(); 771 772 // This is a an attempt to fix bug 7137389 where the device comes back on but the entire 773 // layout is blank but forcing a layout causes it to reappear (e.g. with with 774 // hierarchyviewer). 775 requestLayout(); 776 777 if (mViewStateManager != null) { 778 mViewStateManager.showUsabilityHints(); 779 } 780 } 781 782 @Override 783 public void onScreenTurnedOff() { 784 if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s", 785 Integer.toHexString(hashCode()), SystemClock.uptimeMillis())); 786 // Once the screen turns off, we no longer consider this to be first boot and we want the 787 // biometric unlock to start next time keyguard is shown. 788 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); 789 saveStickyWidgetIndex(); 790 checkAppWidgetConsistency(); 791 showPrimarySecurityScreen(true); 792 getSecurityView(mCurrentSecuritySelection).onPause(); 793 CameraWidgetFrame cameraPage = findCameraPage(); 794 if (cameraPage != null) { 795 cameraPage.onScreenTurnedOff(); 796 } 797 } 798 799 @Override 800 public void show() { 801 if (DEBUG) Log.d(TAG, "show()"); 802 showPrimarySecurityScreen(false); 803 } 804 805 private boolean isSecure() { 806 SecurityMode mode = mSecurityModel.getSecurityMode(); 807 switch (mode) { 808 case Pattern: 809 return mLockPatternUtils.isLockPatternEnabled(); 810 case Password: 811 case PIN: 812 return mLockPatternUtils.isLockPasswordEnabled(); 813 case SimPin: 814 case SimPuk: 815 case Account: 816 return true; 817 case None: 818 return false; 819 default: 820 throw new IllegalStateException("Unknown security mode " + mode); 821 } 822 } 823 824 @Override 825 public void wakeWhenReadyTq(int keyCode) { 826 if (DEBUG) Log.d(TAG, "onWakeKey"); 827 if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) { 828 if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); 829 showSecurityScreen(SecurityMode.None); 830 } else { 831 if (DEBUG) Log.d(TAG, "poking wake lock immediately"); 832 } 833 if (mViewMediatorCallback != null) { 834 mViewMediatorCallback.wakeUp(); 835 } 836 } 837 838 @Override 839 public void verifyUnlock() { 840 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 841 if (securityMode == KeyguardSecurityModel.SecurityMode.None) { 842 if (mViewMediatorCallback != null) { 843 mViewMediatorCallback.keyguardDone(true); 844 } 845 } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern 846 && securityMode != KeyguardSecurityModel.SecurityMode.PIN 847 && securityMode != KeyguardSecurityModel.SecurityMode.Password) { 848 // can only verify unlock when in pattern/password mode 849 if (mViewMediatorCallback != null) { 850 mViewMediatorCallback.keyguardDone(false); 851 } 852 } else { 853 // otherwise, go to the unlock screen, see if they can verify it 854 mIsVerifyUnlockOnly = true; 855 showSecurityScreen(securityMode); 856 } 857 } 858 859 private int getSecurityViewIdForMode(SecurityMode securityMode) { 860 switch (securityMode) { 861 case None: return R.id.keyguard_selector_view; 862 case Pattern: return R.id.keyguard_pattern_view; 863 case PIN: return R.id.keyguard_pin_view; 864 case Password: return R.id.keyguard_password_view; 865 case Biometric: return R.id.keyguard_face_unlock_view; 866 case Account: return R.id.keyguard_account_view; 867 case SimPin: return R.id.keyguard_sim_pin_view; 868 case SimPuk: return R.id.keyguard_sim_puk_view; 869 } 870 return 0; 871 } 872 873 private int getLayoutIdFor(SecurityMode securityMode) { 874 switch (securityMode) { 875 case None: return R.layout.keyguard_selector_view; 876 case Pattern: return R.layout.keyguard_pattern_view; 877 case PIN: return R.layout.keyguard_pin_view; 878 case Password: return R.layout.keyguard_password_view; 879 case Biometric: return R.layout.keyguard_face_unlock_view; 880 case Account: return R.layout.keyguard_account_view; 881 case SimPin: return R.layout.keyguard_sim_pin_view; 882 case SimPuk: return R.layout.keyguard_sim_puk_view; 883 default: 884 return 0; 885 } 886 } 887 888 private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) { 889 AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId); 890 if (appWidgetInfo != null) { 891 AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo); 892 addWidget(view, pageIndex); 893 return true; 894 } else { 895 if (updateDbIfFailed) { 896 Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting"); 897 mAppWidgetHost.deleteAppWidgetId(appId); 898 mLockPatternUtils.removeAppWidget(appId); 899 } 900 return false; 901 } 902 } 903 904 private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks = 905 new CameraWidgetFrame.Callbacks() { 906 @Override 907 public void onLaunchingCamera() { 908 setSliderHandleAlpha(0); 909 } 910 911 @Override 912 public void onCameraLaunchedSuccessfully() { 913 if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) { 914 mAppWidgetContainer.scrollLeft(); 915 } 916 setSliderHandleAlpha(1); 917 mShowSecurityWhenReturn = true; 918 } 919 920 @Override 921 public void onCameraLaunchedUnsuccessfully() { 922 setSliderHandleAlpha(1); 923 } 924 925 private void setSliderHandleAlpha(float alpha) { 926 SlidingChallengeLayout slider = 927 (SlidingChallengeLayout) findViewById(R.id.sliding_layout); 928 if (slider != null) { 929 slider.setHandleAlpha(alpha); 930 } 931 } 932 }; 933 934 private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { 935 @Override 936 Context getContext() { 937 return mContext; 938 } 939 940 @Override 941 KeyguardSecurityCallback getCallback() { 942 return mCallback; 943 } 944 945 @Override 946 LockPatternUtils getLockPatternUtils() { 947 return mLockPatternUtils; 948 } 949 }; 950 951 private void addDefaultWidgets() { 952 LayoutInflater inflater = LayoutInflater.from(mContext); 953 inflater.inflate(R.layout.keyguard_transport_control_view, this, true); 954 955 if (!mSafeModeEnabled && !widgetsDisabledByDpm()) { 956 View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false); 957 mAppWidgetContainer.addWidget(addWidget); 958 View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view); 959 addWidgetButton.setOnClickListener(new OnClickListener() { 960 @Override 961 public void onClick(View v) { 962 int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); 963 if (appWidgetId != -1) { 964 mActivityLauncher.launchWidgetPicker(appWidgetId); 965 } else { 966 Log.e(TAG, "Unable to allocate an AppWidget id in lock screen"); 967 } 968 } 969 }); 970 } 971 972 // We currently disable cameras in safe mode because we support loading 3rd party 973 // cameras we can't trust. TODO: plumb safe mode into camera creation code and only 974 // inflate system-provided camera? 975 if (!mSafeModeEnabled && !cameraDisabledByDpm() 976 && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) { 977 View cameraWidget = 978 CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher); 979 if (cameraWidget != null) { 980 mAppWidgetContainer.addWidget(cameraWidget); 981 } 982 } 983 984 enableUserSelectorIfNecessary(); 985 initializeTransportControl(); 986 } 987 988 private void removeTransportFromWidgetPager() { 989 int page = getWidgetPosition(R.id.keyguard_transport_control); 990 if (page != -1) { 991 mAppWidgetContainer.removeWidget(mTransportControl); 992 993 // XXX keep view attached so we still get show/hide events from AudioManager 994 KeyguardHostView.this.addView(mTransportControl); 995 mTransportControl.setVisibility(View.GONE); 996 mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE); 997 mTransportControl.post(mSwitchPageRunnable); 998 } 999 } 1000 1001 private void addTransportToWidgetPager() { 1002 if (getWidgetPosition(R.id.keyguard_transport_control) == -1) { 1003 KeyguardHostView.this.removeView(mTransportControl); 1004 // insert to left of camera if it exists, otherwise after right-most widget 1005 int lastWidget = mAppWidgetContainer.getChildCount() - 1; 1006 int position = 0; // handle no widget case 1007 if (lastWidget >= 0) { 1008 position = mAppWidgetContainer.isCameraPage(lastWidget) ? 1009 lastWidget : lastWidget + 1; 1010 } 1011 mAppWidgetContainer.addWidget(mTransportControl, position); 1012 mTransportControl.setVisibility(View.VISIBLE); 1013 } 1014 } 1015 1016 private void initializeTransportControl() { 1017 mTransportControl = 1018 (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control); 1019 mTransportControl.setVisibility(View.GONE); 1020 1021 // This code manages showing/hiding the transport control. We keep it around and only 1022 // add it to the hierarchy if it needs to be present. 1023 if (mTransportControl != null) { 1024 mTransportControl.setKeyguardCallback(new TransportCallback() { 1025 @Override 1026 public void onListenerDetached() { 1027 removeTransportFromWidgetPager(); 1028 mTransportControl.post(mSwitchPageRunnable); 1029 } 1030 1031 @Override 1032 public void onListenerAttached() { 1033 // Transport will be added when playstate changes... 1034 mTransportControl.post(mSwitchPageRunnable); 1035 } 1036 1037 @Override 1038 public void onPlayStateChanged() { 1039 mTransportControl.post(mSwitchPageRunnable); 1040 } 1041 }); 1042 } 1043 } 1044 1045 private int getInsertPageIndex() { 1046 View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget); 1047 int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget); 1048 if (insertionIndex < 0) { 1049 insertionIndex = 0; // no add widget page found 1050 } else { 1051 insertionIndex++; // place after add widget 1052 } 1053 return insertionIndex; 1054 } 1055 1056 private void addDefaultStatusWidget(int index) { 1057 LayoutInflater inflater = LayoutInflater.from(mContext); 1058 View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true); 1059 mAppWidgetContainer.addWidget(statusWidget, index); 1060 } 1061 1062 private void addWidgetsFromSettings() { 1063 if (mSafeModeEnabled || widgetsDisabledByDpm()) { 1064 return; 1065 } 1066 1067 int insertionIndex = getInsertPageIndex(); 1068 1069 // Add user-selected widget 1070 final int[] widgets = mLockPatternUtils.getAppWidgets(); 1071 1072 if (widgets == null) { 1073 Log.d(TAG, "Problem reading widgets"); 1074 } else { 1075 for (int i = widgets.length -1; i >= 0; i--) { 1076 if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) { 1077 addDefaultStatusWidget(insertionIndex); 1078 } else { 1079 // We add the widgets from left to right, starting after the first page after 1080 // the add page. We count down, since the order will be persisted from right 1081 // to left, starting after camera. 1082 addWidget(widgets[i], insertionIndex, true); 1083 } 1084 } 1085 } 1086 } 1087 1088 private int allocateIdForDefaultAppWidget() { 1089 int appWidgetId; 1090 Resources res = getContext().getResources(); 1091 ComponentName defaultAppWidget = new ComponentName( 1092 res.getString(R.string.widget_default_package_name), 1093 res.getString(R.string.widget_default_class_name)); 1094 1095 // Note: we don't support configuring the widget 1096 appWidgetId = mAppWidgetHost.allocateAppWidgetId(); 1097 1098 try { 1099 mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget); 1100 1101 } catch (IllegalArgumentException e) { 1102 Log.e(TAG, "Error when trying to bind default AppWidget: " + e); 1103 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 1104 appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; 1105 } 1106 return appWidgetId; 1107 } 1108 public void checkAppWidgetConsistency() { 1109 // Since this method may bind a widget (which we can't do until boot completed) we 1110 // may have to defer it until after boot complete. 1111 if (!mBootCompleted) { 1112 mCheckAppWidgetConsistencyOnBootCompleted = true; 1113 return; 1114 } 1115 final int childCount = mAppWidgetContainer.getChildCount(); 1116 boolean widgetPageExists = false; 1117 for (int i = 0; i < childCount; i++) { 1118 if (mAppWidgetContainer.isWidgetPage(i)) { 1119 widgetPageExists = true; 1120 break; 1121 } 1122 } 1123 if (!widgetPageExists) { 1124 final int insertPageIndex = getInsertPageIndex(); 1125 1126 final boolean userAddedWidgetsEnabled = !widgetsDisabledByDpm(); 1127 boolean addedDefaultAppWidget = false; 1128 1129 if (!mSafeModeEnabled) { 1130 if (userAddedWidgetsEnabled) { 1131 int appWidgetId = allocateIdForDefaultAppWidget(); 1132 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 1133 addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true); 1134 } 1135 } else { 1136 // note: even if widgetsDisabledByDpm() returns true, we still bind/create 1137 // the default appwidget if possible 1138 int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId(); 1139 if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { 1140 appWidgetId = allocateIdForDefaultAppWidget(); 1141 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 1142 mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId); 1143 } 1144 } 1145 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 1146 addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false); 1147 if (!addedDefaultAppWidget) { 1148 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 1149 mLockPatternUtils.writeFallbackAppWidgetId( 1150 AppWidgetManager.INVALID_APPWIDGET_ID); 1151 } 1152 } 1153 } 1154 } 1155 1156 // Use the built-in status/clock view if we can't inflate the default widget 1157 if (!addedDefaultAppWidget) { 1158 addDefaultStatusWidget(insertPageIndex); 1159 } 1160 1161 // trigger DB updates only if user-added widgets are enabled 1162 if (!mSafeModeEnabled && userAddedWidgetsEnabled) { 1163 mAppWidgetContainer.onAddView( 1164 mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex); 1165 } 1166 } 1167 } 1168 1169 Runnable mSwitchPageRunnable = new Runnable() { 1170 @Override 1171 public void run() { 1172 showAppropriateWidgetPage(); 1173 } 1174 }; 1175 1176 static class SavedState extends BaseSavedState { 1177 int transportState; 1178 1179 SavedState(Parcelable superState) { 1180 super(superState); 1181 } 1182 1183 private SavedState(Parcel in) { 1184 super(in); 1185 this.transportState = in.readInt(); 1186 } 1187 1188 @Override 1189 public void writeToParcel(Parcel out, int flags) { 1190 super.writeToParcel(out, flags); 1191 out.writeInt(this.transportState); 1192 } 1193 1194 public static final Parcelable.Creator<SavedState> CREATOR 1195 = new Parcelable.Creator<SavedState>() { 1196 public SavedState createFromParcel(Parcel in) { 1197 return new SavedState(in); 1198 } 1199 1200 public SavedState[] newArray(int size) { 1201 return new SavedState[size]; 1202 } 1203 }; 1204 } 1205 1206 @Override 1207 public Parcelable onSaveInstanceState() { 1208 if (DEBUG) Log.d(TAG, "onSaveInstanceState"); 1209 saveStickyWidgetIndex(); 1210 Parcelable superState = super.onSaveInstanceState(); 1211 SavedState ss = new SavedState(superState); 1212 ss.transportState = mViewStateManager.getTransportState(); 1213 return ss; 1214 } 1215 1216 @Override 1217 public void onRestoreInstanceState(Parcelable state) { 1218 if (DEBUG) Log.d(TAG, "onRestoreInstanceState"); 1219 if (!(state instanceof SavedState)) { 1220 super.onRestoreInstanceState(state); 1221 return; 1222 } 1223 SavedState ss = (SavedState) state; 1224 super.onRestoreInstanceState(ss.getSuperState()); 1225 mViewStateManager.setTransportState(ss.transportState); 1226 post(mSwitchPageRunnable); 1227 } 1228 1229 @Override 1230 public void onWindowFocusChanged(boolean hasWindowFocus) { 1231 super.onWindowFocusChanged(hasWindowFocus); 1232 if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused")); 1233 if (!hasWindowFocus) { 1234 saveStickyWidgetIndex(); 1235 } else if (mShowSecurityWhenReturn) { 1236 SlidingChallengeLayout slider = 1237 (SlidingChallengeLayout) findViewById(R.id.sliding_layout); 1238 if (slider != null) { 1239 slider.setHandleAlpha(1); 1240 slider.showChallenge(true); 1241 } 1242 mShowSecurityWhenReturn = false; 1243 } 1244 } 1245 1246 private void showAppropriateWidgetPage() { 1247 int state = mViewStateManager.getTransportState(); 1248 boolean isMusicPlaying = mTransportControl.isMusicPlaying() 1249 || state == KeyguardViewStateManager.TRANSPORT_VISIBLE; 1250 if (isMusicPlaying) { 1251 mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE); 1252 addTransportToWidgetPager(); 1253 } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) { 1254 mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE); 1255 } 1256 int pageToShow = getAppropriateWidgetPage(isMusicPlaying); 1257 mAppWidgetContainer.setCurrentPage(pageToShow); 1258 } 1259 1260 private CameraWidgetFrame findCameraPage() { 1261 for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) { 1262 if (mAppWidgetContainer.isCameraPage(i)) { 1263 return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i); 1264 } 1265 } 1266 return null; 1267 } 1268 1269 private int getStickyWidget() { 1270 // The first time we query the persistent state. From that point, we use a locally updated 1271 // notion of the sticky widget page. 1272 if (!mPersitentStickyWidgetLoaded) { 1273 mLocalStickyWidget = mLockPatternUtils.getStickyAppWidgetIndex(); 1274 mPersitentStickyWidgetLoaded = true; 1275 } 1276 return mLocalStickyWidget; 1277 } 1278 1279 public void updateStickyWidget(int index) { 1280 if (index < 0 || index >= mAppWidgetContainer.getChildCount()) { 1281 return; 1282 } 1283 if (mAppWidgetContainer.isAddPage(index)) { 1284 return; 1285 } 1286 if (mAppWidgetContainer.isCameraPage(index)) { 1287 return; 1288 } 1289 if (isMusicPage(index)) { 1290 return; 1291 } 1292 1293 mLocalStickyWidget = index; 1294 } 1295 1296 boolean isMusicPage(int pageIndex) { 1297 return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control); 1298 } 1299 1300 private int getAppropriateWidgetPage(boolean isMusicPlaying) { 1301 // assumes at least one widget (besides camera + add) 1302 1303 // if music playing, show transport 1304 if (isMusicPlaying) { 1305 if (DEBUG) Log.d(TAG, "Music playing, show transport"); 1306 return mAppWidgetContainer.getWidgetPageIndex(mTransportControl); 1307 } 1308 1309 // if we have a valid sticky widget, show it 1310 int stickyWidgetIndex = getStickyWidget(); 1311 if (stickyWidgetIndex > -1 1312 && stickyWidgetIndex < mAppWidgetContainer.getChildCount() 1313 && !mAppWidgetContainer.isAddPage(stickyWidgetIndex) 1314 && !mAppWidgetContainer.isCameraPage(stickyWidgetIndex)) { 1315 if (DEBUG) Log.d(TAG, "Valid sticky widget found, show page " + stickyWidgetIndex); 1316 return stickyWidgetIndex; 1317 } 1318 1319 // else show the right-most widget (except for camera) 1320 int rightMost = mAppWidgetContainer.getChildCount() - 1; 1321 if (mAppWidgetContainer.isCameraPage(rightMost)) { 1322 rightMost--; 1323 } 1324 if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost); 1325 return rightMost; 1326 } 1327 1328 private void saveStickyWidgetIndex() { 1329 if (DEBUG) Log.d(TAG, "saveStickyWidgetIndex: " + mLocalStickyWidget); 1330 if (mPersitentStickyWidgetLoaded && mLocalStickyWidget >= 0) { 1331 mLockPatternUtils.setStickyAppWidgetIndex(mLocalStickyWidget); 1332 } 1333 } 1334 1335 private void enableUserSelectorIfNecessary() { 1336 if (!UserManager.supportsMultipleUsers()) { 1337 return; // device doesn't support multi-user mode 1338 } 1339 1340 // if there are multiple users, we need to enable to multi-user switcher 1341 UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1342 List<UserInfo> users = mUm.getUsers(true); 1343 1344 if (users.size() > 1) { 1345 KeyguardMultiUserSelectorView multiUser = 1346 (KeyguardMultiUserSelectorView) findViewById(R.id.keyguard_user_selector); 1347 multiUser.setVisibility(View.VISIBLE); 1348 multiUser.addUsers(mUm.getUsers(true)); 1349 UserSwitcherCallback callback = new UserSwitcherCallback() { 1350 @Override 1351 public void hideSecurityView(int duration) { 1352 mSecurityViewContainer.animate().alpha(0).setDuration(duration); 1353 } 1354 1355 @Override 1356 public void showSecurityView() { 1357 mSecurityViewContainer.setAlpha(1.0f); 1358 } 1359 1360 @Override 1361 public void showUnlockHint() { 1362 if (mKeyguardSelectorView != null) { 1363 mKeyguardSelectorView.showUsabilityHint(); 1364 } 1365 } 1366 1367 @Override 1368 public void userActivity() { 1369 if (mViewMediatorCallback != null) { 1370 mViewMediatorCallback.userActivity(); 1371 } 1372 } 1373 }; 1374 multiUser.setCallback(callback); 1375 } 1376 } 1377 1378 @Override 1379 public void cleanUp() { 1380 1381 } 1382 1383 /** 1384 * In general, we enable unlocking the insecure keyguard with the menu key. However, there are 1385 * some cases where we wish to disable it, notably when the menu button placement or technology 1386 * is prone to false positives. 1387 * 1388 * @return true if the menu key should be enabled 1389 */ 1390 private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; 1391 private boolean shouldEnableMenuKey() { 1392 final Resources res = getResources(); 1393 final boolean configDisabled = res.getBoolean( 1394 com.android.internal.R.bool.config_disableMenuKeyInLockScreen); 1395 final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); 1396 final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); 1397 return !configDisabled || isTestHarness || fileOverride; 1398 } 1399 1400 1401 1402 public void goToUserSwitcher() { 1403 mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector)); 1404 } 1405 1406 public boolean handleMenuKey() { 1407 // The following enables the MENU key to work for testing automation 1408 if (shouldEnableMenuKey()) { 1409 showNextSecurityScreenOrFinish(false); 1410 return true; 1411 } 1412 return false; 1413 } 1414 1415 public boolean handleBackKey() { 1416 if (mCurrentSecuritySelection != SecurityMode.None) { 1417 mCallback.dismiss(false); 1418 return true; 1419 } 1420 return false; 1421 } 1422 1423 /** 1424 * Dismisses the keyguard by going to the next screen or making it gone. 1425 */ 1426 public void dismiss() { 1427 showNextSecurityScreenOrFinish(false); 1428 } 1429} 1430