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