KeyguardHostView.java revision 000464ac012471d301c6e48a8228291519915e17
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.Context; 29import android.content.Intent; 30import android.content.IntentSender; 31import android.content.SharedPreferences; 32import android.content.res.Resources; 33import android.graphics.Canvas; 34import android.telephony.TelephonyManager; 35import android.util.AttributeSet; 36import android.util.Log; 37import android.util.Slog; 38import android.view.KeyEvent; 39import android.view.View; 40import android.view.WindowManager; 41import android.view.animation.AnimationUtils; 42import android.widget.Button; 43import android.widget.ViewFlipper; 44import android.widget.RemoteViews.OnClickHandler; 45 46import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode; 47import com.android.internal.widget.LockPatternUtils; 48import com.android.internal.R; 49 50import java.io.File; 51import java.util.ArrayList; 52 53public class KeyguardHostView extends KeyguardViewBase { 54 // Use this to debug all of keyguard 55 public static boolean DEBUG; 56 57 static final int APPWIDGET_HOST_ID = 0x4B455947; 58 private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs"; 59 60 // time after launching EmergencyDialer before the screen goes blank. 61 private static final int EMERGENCY_CALL_TIMEOUT = 10000; 62 63 // intent action for launching emergency dialer activity. 64 static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; 65 66 private static final String TAG = "KeyguardViewHost"; 67 68 private static final int SECURITY_SELECTOR_ID = R.id.keyguard_selector_view; 69 private static final int SECURITY_PATTERN_ID = R.id.keyguard_pattern_view; 70 private static final int SECURITY_PASSWORD_ID = R.id.keyguard_password_view; 71 private static final int SECURITY_BIOMETRIC_ID = R.id.keyguard_face_unlock_view; 72 private static final int SECURITY_SIM_PIN_ID = R.id.keyguard_sim_pin_view; 73 private static final int SECURITY_SIM_PUK_ID = R.id.keyguard_sim_puk_view; 74 private static final int SECURITY_ACCOUNT_ID = R.id.keyguard_account_view; 75 76 private AppWidgetHost mAppWidgetHost; 77 private KeyguardWidgetPager mAppWidgetContainer; 78 private ViewFlipper mViewFlipper; 79 private Button mEmergencyDialerButton; 80 private boolean mEnableMenuKey; 81 private boolean mIsVerifyUnlockOnly; 82 private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView 83 private int mCurrentSecurityId = SECURITY_SELECTOR_ID; 84 85 // KeyguardSecurityViews 86 final private int [] mViewIds = { 87 SECURITY_SELECTOR_ID, 88 SECURITY_PATTERN_ID, 89 SECURITY_PASSWORD_ID, 90 SECURITY_BIOMETRIC_ID, 91 SECURITY_SIM_PIN_ID, 92 SECURITY_SIM_PUK_ID, 93 SECURITY_ACCOUNT_ID, 94 }; 95 96 private ArrayList<View> mViews = new ArrayList<View>(mViewIds.length); 97 98 protected Runnable mLaunchRunnable; 99 100 protected int mFailedAttempts; 101 private LockPatternUtils mLockPatternUtils; 102 103 private KeyguardSecurityModel mSecurityModel; 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(mContext, APPWIDGET_HOST_ID, mOnClickHandler); 113 mSecurityModel = new KeyguardSecurityModel(mContext); 114 115 // The following enables the MENU key to work for testing automation 116 mEnableMenuKey = shouldEnableMenuKey(); 117 setFocusable(true); 118 setFocusableInTouchMode(true); 119 } 120 121 @Override 122 protected void dispatchDraw(Canvas canvas) { 123 super.dispatchDraw(canvas); 124 mViewMediatorCallback.keyguardDoneDrawing(); 125 } 126 127 @Override 128 protected void onFinishInflate() { 129 mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container); 130 mAppWidgetContainer.setVisibility(VISIBLE); 131 132 // View Flipper 133 mViewFlipper = (ViewFlipper) findViewById(R.id.view_flipper); 134 135 // Initialize all security views 136 for (int i = 0; i < mViewIds.length; i++) { 137 View view = findViewById(mViewIds[i]); 138 mViews.add(view); 139 if (view != null) { 140 ((KeyguardSecurityView) view).setKeyguardCallback(mCallback); 141 } else { 142 Log.v("*********", "Can't find view id " + mViewIds[i]); 143 } 144 } 145 146 // Enable emergency dialer button 147 mEmergencyDialerButton = (Button) findViewById(R.id.emergency_call_button); 148 mEmergencyDialerButton.setOnClickListener(new OnClickListener() { 149 public void onClick(View v) { 150 takeEmergencyCallAction(); 151 } 152 }); 153 } 154 155 void setLockPatternUtils(LockPatternUtils utils) { 156 mSecurityModel.setLockPatternUtils(utils); 157 mLockPatternUtils = utils; 158 for (int i = 0; i < mViews.size(); i++) { 159 KeyguardSecurityView ksv = (KeyguardSecurityView) mViews.get(i); 160 if (ksv != null) { 161 ksv.setLockPatternUtils(utils); 162 } else { 163 Log.w(TAG, "**** ksv was null at " + i); 164 } 165 } 166 } 167 168 @Override 169 protected void onAttachedToWindow() { 170 super.onAttachedToWindow(); 171 mAppWidgetHost.startListening(); 172 maybePopulateWidgets(); 173 } 174 175 @Override 176 protected void onDetachedFromWindow() { 177 super.onDetachedFromWindow(); 178 mAppWidgetHost.stopListening(); 179 } 180 181 AppWidgetHost getAppWidgetHost() { 182 return mAppWidgetHost; 183 } 184 185 void addWidget(AppWidgetHostView view) { 186 mAppWidgetContainer.addWidget(view); 187 } 188 189 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { 190 191 public void userActivity(long timeout) { 192 mViewMediatorCallback.pokeWakelock(timeout); 193 } 194 195 public void dismiss(boolean authenticated) { 196 showNextSecurityScreenOrFinish(authenticated); 197 } 198 199 public boolean isVerifyUnlockOnly() { 200 return mIsVerifyUnlockOnly; 201 } 202 203 public void reportSuccessfulUnlockAttempt() { 204 KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts(); 205 } 206 207 public void reportFailedUnlockAttempt() { 208 // TODO: handle biometric attempt differently. 209 KeyguardHostView.this.reportFailedUnlockAttempt(); 210 } 211 212 public int getFailedAttempts() { 213 return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(); 214 } 215 216 @Override 217 public void showBackupSecurity() { 218 KeyguardHostView.this.showBackupSecurity(); 219 } 220 221 @Override 222 public void setOnDismissRunnable(Runnable runnable) { 223 KeyguardHostView.this.setOnDismissRunnable(runnable); 224 } 225 226 }; 227 228 /** 229 * Shows the emergency dialer or returns the user to the existing call. 230 */ 231 public void takeEmergencyCallAction() { 232 mCallback.userActivity(EMERGENCY_CALL_TIMEOUT); 233 if (TelephonyManager.getDefault().getCallState() 234 == TelephonyManager.CALL_STATE_OFFHOOK) { 235 mLockPatternUtils.resumeCall(); 236 } else { 237 Intent intent = new Intent(ACTION_EMERGENCY_DIAL); 238 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 239 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 240 getContext().startActivity(intent); 241 } 242 } 243 244 private void showDialog(String title, String message) { 245 final AlertDialog dialog = new AlertDialog.Builder(mContext) 246 .setTitle(title) 247 .setMessage(message) 248 .setNeutralButton(com.android.internal.R.string.ok, null) 249 .create(); 250 if (!(mContext instanceof Activity)) { 251 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 252 } 253 dialog.show(); 254 } 255 256 private void showTimeoutDialog() { 257 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 258 int messageId = 0; 259 260 switch (mSecurityModel.getSecurityMode()) { 261 case Pattern: 262 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message; 263 break; 264 265 case Password: { 266 final boolean isPin = mLockPatternUtils.getKeyguardStoredPasswordQuality() == 267 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 268 messageId = isPin ? R.string.kg_too_many_failed_pin_attempts_dialog_message 269 : R.string.kg_too_many_failed_password_attempts_dialog_message; 270 } 271 break; 272 } 273 274 if (messageId != 0) { 275 final String message = mContext.getString(messageId, 276 KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(), 277 timeoutInSeconds); 278 showDialog(null, message); 279 } 280 } 281 282 private void showAlmostAtWipeDialog(int attempts, int remaining) { 283 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 284 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe, 285 attempts, remaining); 286 showDialog(null, message); 287 } 288 289 private void showWipeDialog(int attempts) { 290 String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts); 291 showDialog(null, message); 292 } 293 294 private void showAlmostAtAccountLoginDialog() { 295 final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; 296 final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 297 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 298 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login, 299 count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); 300 showDialog(null, message); 301 } 302 303 private void reportFailedUnlockAttempt() { 304 final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); 305 final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time 306 307 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); 308 309 SecurityMode mode = mSecurityModel.getSecurityMode(); 310 final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern; 311 312 final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager() 313 .getMaximumFailedPasswordsForWipe(null); 314 315 final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 316 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; 317 318 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? 319 (failedAttemptsBeforeWipe - failedAttempts) 320 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction 321 322 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { 323 // If we reach this code, it means the user has installed a DevicePolicyManager 324 // that requests device wipe after N attempts. Once we get below the grace 325 // period, we'll post this dialog every time as a clear warning until the 326 // bombshell hits and the device is wiped. 327 if (remainingBeforeWipe > 0) { 328 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe); 329 } else { 330 // Too many attempts. The device will be wiped shortly. 331 Slog.i(TAG, "Too many unlock attempts; device will be wiped!"); 332 showWipeDialog(failedAttempts); 333 } 334 } else { 335 boolean showTimeout = 336 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0; 337 if (usingPattern && mEnableFallback) { 338 if (failedAttempts == failedAttemptWarning) { 339 showAlmostAtAccountLoginDialog(); 340 showTimeout = false; // don't show both dialogs 341 } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { 342 mLockPatternUtils.setPermanentlyLocked(true); 343 showSecurityScreen(SECURITY_ACCOUNT_ID); 344 // don't show timeout dialog because we show account unlock screen next 345 showTimeout = false; 346 } 347 } 348 if (showTimeout) { 349 showTimeoutDialog(); 350 } 351 } 352 monitor.reportFailedUnlockAttempt(); 353 mLockPatternUtils.reportFailedPasswordAttempt(); 354 } 355 356 /** 357 * Shows the backup security screen for the current security mode. This could be used for 358 * password recovery screens but is currently only used for pattern unlock to show the 359 * account unlock screen and biometric unlock to show the user's normal unlock. 360 */ 361 private void showBackupSecurity() { 362 SecurityMode currentMode = mSecurityModel.getAlternateFor(mSecurityModel.getSecurityMode()); 363 SecurityMode backup = mSecurityModel.getBackupFor(currentMode); 364 showSecurityScreen(getSecurityViewIdForMode(backup)); 365 } 366 367 private void showNextSecurityScreenOrFinish(boolean authenticated) { 368 boolean finish = false; 369 if (SECURITY_SELECTOR_ID == mCurrentSecurityId) { 370 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 371 // Allow an alternate, such as biometric unlock 372 securityMode = mSecurityModel.getAlternateFor(securityMode); 373 int realSecurityId = getSecurityViewIdForMode(securityMode); 374 if (SECURITY_SELECTOR_ID == realSecurityId) { 375 finish = true; // no security required 376 } else { 377 showSecurityScreen(realSecurityId); // switch to the "real" security view 378 } 379 } else if (authenticated) { 380 switch (mCurrentSecurityId) { 381 case SECURITY_PATTERN_ID: 382 case SECURITY_PASSWORD_ID: 383 case SECURITY_ACCOUNT_ID: 384 case SECURITY_BIOMETRIC_ID: 385 finish = true; 386 break; 387 388 case SECURITY_SIM_PIN_ID: 389 case SECURITY_SIM_PUK_ID: 390 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home 391 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 392 if (securityMode != SecurityMode.None) { 393 showSecurityScreen(getSecurityViewIdForMode(securityMode)); 394 } else { 395 finish = true; 396 } 397 break; 398 399 default: 400 showSecurityScreen(SECURITY_SELECTOR_ID); 401 break; 402 } 403 } else { 404 // Not authenticated but we were asked to dismiss so go back to selector screen. 405 showSecurityScreen(SECURITY_SELECTOR_ID); 406 } 407 if (finish) { 408 // If there's a pending runnable because the user interacted with a widget 409 // and we're leaving keyguard, then run it. 410 if (mLaunchRunnable != null) { 411 mLaunchRunnable.run(); 412 mViewFlipper.setDisplayedChild(0); 413 mLaunchRunnable = null; 414 } 415 mViewMediatorCallback.keyguardDone(true); 416 } 417 } 418 419 private OnClickHandler mOnClickHandler = new OnClickHandler() { 420 @Override 421 public boolean onClickHandler(final View view, 422 final android.app.PendingIntent pendingIntent, 423 final Intent fillInIntent) { 424 if (pendingIntent.isActivity()) { 425 setOnDismissRunnable(new Runnable() { 426 public void run() { 427 try { 428 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? 429 Context context = view.getContext(); 430 ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, 431 0, 0, 432 view.getMeasuredWidth(), view.getMeasuredHeight()); 433 context.startIntentSender( 434 pendingIntent.getIntentSender(), fillInIntent, 435 Intent.FLAG_ACTIVITY_NEW_TASK, 436 Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle()); 437 } catch (IntentSender.SendIntentException e) { 438 android.util.Log.e(TAG, "Cannot send pending intent: ", e); 439 } catch (Exception e) { 440 android.util.Log.e(TAG, "Cannot send pending intent due to " + 441 "unknown exception: ", e); 442 } 443 } 444 }); 445 446 mCallback.dismiss(false); 447 return true; 448 } else { 449 return super.onClickHandler(view, pendingIntent, fillInIntent); 450 } 451 }; 452 }; 453 454 @Override 455 public void reset() { 456 mIsVerifyUnlockOnly = false; 457 requestFocus(); 458 } 459 460 /** 461 * Sets a runnable to run when keyguard is dismissed 462 * @param runnable 463 */ 464 protected void setOnDismissRunnable(Runnable runnable) { 465 mLaunchRunnable = runnable; 466 } 467 468 private KeyguardSecurityView getSecurityView(int securitySelectorId) { 469 final int children = mViewFlipper.getChildCount(); 470 for (int child = 0; child < children; child++) { 471 if (mViewFlipper.getChildAt(child).getId() == securitySelectorId) { 472 return ((KeyguardSecurityView)mViewFlipper.getChildAt(child)); 473 } 474 } 475 return null; 476 } 477 478 /** 479 * Switches to the given security view unless it's already being shown, in which case 480 * this is a no-op. 481 * 482 * @param securityViewId 483 */ 484 private void showSecurityScreen(int securityViewId) { 485 486 if (securityViewId == mCurrentSecurityId) return; 487 488 KeyguardSecurityView oldView = getSecurityView(mCurrentSecurityId); 489 KeyguardSecurityView newView = getSecurityView(securityViewId); 490 491 // Emulate Activity life cycle 492 oldView.onPause(); 493 newView.onResume(); 494 495 mViewMediatorCallback.setNeedsInput(newView.needsInput()); 496 497 // Find and show this child. 498 final int childCount = mViewFlipper.getChildCount(); 499 500 // If we're go to/from the selector view, do flip animation, otherwise use fade animation. 501 final boolean doFlip = mCurrentSecurityId == SECURITY_SELECTOR_ID 502 || securityViewId == SECURITY_SELECTOR_ID; 503 final int inAnimation = doFlip ? R.anim.keyguard_security_animate_in 504 : R.anim.keyguard_security_fade_in; 505 final int outAnimation = doFlip ? R.anim.keyguard_security_animate_out 506 : R.anim.keyguard_security_fade_out; 507 508 mViewFlipper.setInAnimation(AnimationUtils.loadAnimation(mContext, inAnimation)); 509 mViewFlipper.setOutAnimation(AnimationUtils.loadAnimation(mContext, outAnimation)); 510 for (int i = 0; i < childCount; i++) { 511 if (securityViewId == mViewFlipper.getChildAt(i).getId()) { 512 mViewFlipper.setDisplayedChild(i); 513 break; 514 } 515 } 516 517 // Discard current runnable if we're switching back to the selector view 518 if (securityViewId == SECURITY_SELECTOR_ID) { 519 setOnDismissRunnable(null); 520 } 521 522 mCurrentSecurityId = securityViewId; 523 } 524 525 @Override 526 public void onScreenTurnedOn() { 527 if (DEBUG) Log.d(TAG, "screen on"); 528 showSecurityScreen(mCurrentSecurityId); 529 } 530 531 @Override 532 public void onScreenTurnedOff() { 533 if (DEBUG) Log.d(TAG, "screen off"); 534 showSecurityScreen(SECURITY_SELECTOR_ID); 535 } 536 537 @Override 538 public void show() { 539 onScreenTurnedOn(); 540 } 541 542 private boolean isSecure() { 543 SecurityMode mode = mSecurityModel.getSecurityMode(); 544 switch (mode) { 545 case Pattern: 546 return mLockPatternUtils.isLockPatternEnabled(); 547 case Password: 548 return mLockPatternUtils.isLockPasswordEnabled(); 549 case SimPin: 550 case SimPuk: 551 case Account: 552 return true; 553 case None: 554 return false; 555 default: 556 throw new IllegalStateException("Unknown security mode " + mode); 557 } 558 } 559 560 @Override 561 public void wakeWhenReadyTq(int keyCode) { 562 if (DEBUG) Log.d(TAG, "onWakeKey"); 563 if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) { 564 if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); 565 showSecurityScreen(SECURITY_SELECTOR_ID); 566 mViewMediatorCallback.pokeWakelock(); 567 } else { 568 if (DEBUG) Log.d(TAG, "poking wake lock immediately"); 569 mViewMediatorCallback.pokeWakelock(); 570 } 571 } 572 573 @Override 574 public void verifyUnlock() { 575 SecurityMode securityMode = mSecurityModel.getSecurityMode(); 576 if (securityMode == KeyguardSecurityModel.SecurityMode.None) { 577 mViewMediatorCallback.keyguardDone(true); 578 } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern 579 && securityMode != KeyguardSecurityModel.SecurityMode.Password) { 580 // can only verify unlock when in pattern/password mode 581 mViewMediatorCallback.keyguardDone(false); 582 } else { 583 // otherwise, go to the unlock screen, see if they can verify it 584 mIsVerifyUnlockOnly = true; 585 showSecurityScreen(getSecurityViewIdForMode(securityMode)); 586 } 587 } 588 589 private int getSecurityViewIdForMode(SecurityMode securityMode) { 590 switch (securityMode) { 591 case None: return SECURITY_SELECTOR_ID; 592 case Pattern: return SECURITY_PATTERN_ID; 593 case Password: return SECURITY_PASSWORD_ID; 594 case Biometric: return SECURITY_BIOMETRIC_ID; 595 case Account: return SECURITY_ACCOUNT_ID; 596 case SimPin: return SECURITY_SIM_PIN_ID; 597 case SimPuk: return SECURITY_SIM_PUK_ID; 598 } 599 return 0; 600 } 601 602 private void addWidget(int appId) { 603 AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); 604 AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId); 605 AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo); 606 addWidget(view); 607 } 608 609 private void maybePopulateWidgets() { 610 DevicePolicyManager dpm = 611 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 612 if (dpm != null && dpm.getKeyguardWidgetsDisabled(null) 613 != DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_NONE) { 614 Log.v(TAG, "Keyguard widgets disabled because of device policy admin"); 615 return; 616 } 617 SharedPreferences prefs = mContext.getSharedPreferences( 618 KEYGUARD_WIDGET_PREFS, Context.MODE_PRIVATE); 619 for (String key : prefs.getAll().keySet()) { 620 int appId = prefs.getInt(key, -1); 621 if (appId != -1) { 622 Log.w(TAG, "populate: adding " + key); 623 addWidget(appId); 624 } else { 625 Log.w(TAG, "populate: can't find " + key); 626 } 627 } 628 } 629 630 @Override 631 public void cleanUp() { 632 633 } 634 635 /** 636 * In general, we enable unlocking the insecure keyguard with the menu key. However, there are 637 * some cases where we wish to disable it, notably when the menu button placement or technology 638 * is prone to false positives. 639 * 640 * @return true if the menu key should be enabled 641 */ 642 private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; 643 private boolean shouldEnableMenuKey() { 644 final Resources res = getResources(); 645 final boolean configDisabled = res.getBoolean( 646 com.android.internal.R.bool.config_disableMenuKeyInLockScreen); 647 final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); 648 final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); 649 return !configDisabled || isTestHarness || fileOverride; 650 } 651 652 @Override 653 public boolean onKeyDown(int keyCode, KeyEvent event) { 654 if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKey) { 655 showNextSecurityScreenOrFinish(false); 656 return true; 657 } else { 658 return super.onKeyDown(keyCode, event); 659 } 660 } 661 662} 663