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