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