SecuritySettings.java revision 41b5321e8b8e795941156ff2c8127d34e2dfe1e7
1/* 2 * Copyright (C) 2007 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.settings; 18 19 20import android.app.Activity; 21import android.app.AlertDialog; 22import android.app.Dialog; 23import android.content.ContentQueryMap; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.DialogInterface; 27import android.content.Intent; 28import android.content.pm.PackageManager.NameNotFoundException; 29import android.database.Cursor; 30import android.location.LocationManager; 31import android.os.Bundle; 32import android.preference.CheckBoxPreference; 33import android.preference.EditTextPreference; 34import android.preference.Preference; 35import android.preference.PreferenceActivity; 36import android.preference.PreferenceCategory; 37import android.preference.PreferenceGroup; 38import android.preference.PreferenceScreen; 39import android.provider.Settings; 40import android.security.CertTool; 41import android.security.Keystore; 42import android.text.Html; 43import android.text.TextUtils; 44import android.text.method.LinkMovementMethod; 45import android.view.View; 46import android.widget.TextView; 47import android.widget.Toast; 48 49import com.android.internal.widget.LockPatternUtils; 50import android.telephony.TelephonyManager; 51 52import java.util.ArrayList; 53import java.util.List; 54import java.util.Observable; 55import java.util.Observer; 56 57/** 58 * Gesture lock pattern settings. 59 */ 60public class SecuritySettings extends PreferenceActivity implements 61 DialogInterface.OnDismissListener, DialogInterface.OnClickListener { 62 63 // Lock Settings 64 65 private static final String KEY_LOCK_ENABLED = "lockenabled"; 66 private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; 67 private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback"; 68 private static final int CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE = 55; 69 70 private LockPatternUtils mLockPatternUtils; 71 private CheckBoxPreference mLockEnabled; 72 private CheckBoxPreference mVisiblePattern; 73 private CheckBoxPreference mTactileFeedback; 74 private Preference mChoosePattern; 75 76 private CheckBoxPreference mShowPassword; 77 78 // Location Settings 79 private static final String LOCATION_CATEGORY = "location_category"; 80 private static final String LOCATION_NETWORK = "location_network"; 81 private static final String LOCATION_GPS = "location_gps"; 82 private static final String ASSISTED_GPS = "assisted_gps"; 83 84 // Credential storage 85 public static final String ACTION_ADD_CREDENTIAL = 86 "android.security.ADD_CREDENTIAL"; 87 public static final String ACTION_UNLOCK_CREDENTIAL_STORAGE = 88 "android.security.UNLOCK_CREDENTIAL_STORAGE"; 89 private static final String KEY_CSTOR_TYPE_NAME = "typeName"; 90 private static final String KEY_CSTOR_ITEM = "item"; 91 private static final String KEY_CSTOR_NAMESPACE = "namespace"; 92 private static final String KEY_CSTOR_DESCRIPTION = "description"; 93 private static final int CSTOR_MIN_PASSWORD_LENGTH = 8; 94 95 private static final int CSTOR_INIT_DIALOG = 1; 96 private static final int CSTOR_CHANGE_PASSWORD_DIALOG = 2; 97 private static final int CSTOR_UNLOCK_DIALOG = 3; 98 private static final int CSTOR_RESET_DIALOG = 4; 99 private static final int CSTOR_NAME_CREDENTIAL_DIALOG = 5; 100 101 private CstorHelper mCstorHelper = new CstorHelper(); 102 103 // Vendor specific 104 private static final String GSETTINGS_PROVIDER = "com.google.android.providers.settings"; 105 private static final String USE_LOCATION = "use_location"; 106 private static final String KEY_DONE_USE_LOCATION = "doneLocation"; 107 private CheckBoxPreference mUseLocation; 108 private boolean mOkClicked; 109 private Dialog mUseLocationDialog; 110 111 private CheckBoxPreference mNetwork; 112 private CheckBoxPreference mGps; 113 private CheckBoxPreference mAssistedGps; 114 115 // These provide support for receiving notification when Location Manager settings change. 116 // This is necessary because the Network Location Provider can change settings 117 // if the user does not confirm enabling the provider. 118 private ContentQueryMap mContentQueryMap; 119 private final class SettingsObserver implements Observer { 120 public void update(Observable o, Object arg) { 121 updateToggles(); 122 } 123 } 124 125 @Override 126 protected void onCreate(Bundle savedInstanceState) { 127 super.onCreate(savedInstanceState); 128 addPreferencesFromResource(R.xml.security_settings); 129 130 mLockPatternUtils = new LockPatternUtils(getContentResolver()); 131 132 createPreferenceHierarchy(); 133 134 mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK); 135 mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS); 136 mAssistedGps = (CheckBoxPreference) getPreferenceScreen().findPreference(ASSISTED_GPS); 137 mUseLocation = (CheckBoxPreference) getPreferenceScreen().findPreference(USE_LOCATION); 138 139 // Vendor specific 140 try { 141 if (mUseLocation != null 142 && getPackageManager().getPackageInfo(GSETTINGS_PROVIDER, 0) == null) { 143 ((PreferenceGroup)findPreference(LOCATION_CATEGORY)) 144 .removePreference(mUseLocation); 145 } 146 } catch (NameNotFoundException nnfe) { 147 } 148 updateToggles(); 149 150 // listen for Location Manager settings changes 151 Cursor settingsCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, null, 152 "(" + Settings.System.NAME + "=?)", 153 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, 154 null); 155 mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null); 156 mContentQueryMap.addObserver(new SettingsObserver()); 157 boolean doneUseLocation = savedInstanceState == null 158 ? false : savedInstanceState.getBoolean(KEY_DONE_USE_LOCATION, true); 159 if (!doneUseLocation && (getIntent().getBooleanExtra("SHOW_USE_LOCATION", false) 160 || savedInstanceState != null)) { 161 showUseLocationDialog(true); 162 } 163 164 mCstorHelper.handleCstorIntents(getIntent()); 165 } 166 167 private PreferenceScreen createPreferenceHierarchy() { 168 // Root 169 PreferenceScreen root = this.getPreferenceScreen(); 170 171 // Inline preferences 172 PreferenceCategory inlinePrefCat = new PreferenceCategory(this); 173 inlinePrefCat.setTitle(R.string.lock_settings_title); 174 root.addPreference(inlinePrefCat); 175 176 // autolock toggle 177 mLockEnabled = new LockEnabledPref(this); 178 mLockEnabled.setTitle(R.string.lockpattern_settings_enable_title); 179 mLockEnabled.setSummary(R.string.lockpattern_settings_enable_summary); 180 mLockEnabled.setKey(KEY_LOCK_ENABLED); 181 inlinePrefCat.addPreference(mLockEnabled); 182 183 // visible pattern 184 mVisiblePattern = new CheckBoxPreference(this); 185 mVisiblePattern.setKey(KEY_VISIBLE_PATTERN); 186 mVisiblePattern.setTitle(R.string.lockpattern_settings_enable_visible_pattern_title); 187 inlinePrefCat.addPreference(mVisiblePattern); 188 189 // tactile feedback 190 mTactileFeedback = new CheckBoxPreference(this); 191 mTactileFeedback.setKey(KEY_TACTILE_FEEDBACK_ENABLED); 192 mTactileFeedback.setTitle(R.string.lockpattern_settings_enable_tactile_feedback_title); 193 inlinePrefCat.addPreference(mTactileFeedback); 194 195 // change pattern lock 196 Intent intent = new Intent(); 197 intent.setClassName("com.android.settings", 198 "com.android.settings.ChooseLockPatternTutorial"); 199 mChoosePattern = getPreferenceManager().createPreferenceScreen(this); 200 mChoosePattern.setIntent(intent); 201 inlinePrefCat.addPreference(mChoosePattern); 202 203 int activePhoneType = TelephonyManager.getDefault().getPhoneType(); 204 205 // do not display SIM lock for CDMA phone 206 if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType) 207 { 208 PreferenceScreen simLockPreferences = getPreferenceManager() 209 .createPreferenceScreen(this); 210 simLockPreferences.setTitle(R.string.sim_lock_settings_category); 211 // Intent to launch SIM lock settings 212 intent = new Intent(); 213 intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings"); 214 simLockPreferences.setIntent(intent); 215 216 PreferenceCategory simLockCat = new PreferenceCategory(this); 217 simLockCat.setTitle(R.string.sim_lock_settings_title); 218 root.addPreference(simLockCat); 219 simLockCat.addPreference(simLockPreferences); 220 } 221 222 // Passwords 223 PreferenceCategory passwordsCat = new PreferenceCategory(this); 224 passwordsCat.setTitle(R.string.security_passwords_title); 225 root.addPreference(passwordsCat); 226 227 CheckBoxPreference showPassword = mShowPassword = new CheckBoxPreference(this); 228 showPassword.setKey("show_password"); 229 showPassword.setTitle(R.string.show_password); 230 showPassword.setSummary(R.string.show_password_summary); 231 showPassword.setPersistent(false); 232 passwordsCat.addPreference(showPassword); 233 234 // Credential storage 235 PreferenceCategory credStoreCat = new PreferenceCategory(this); 236 credStoreCat.setTitle(R.string.cstor_settings_category); 237 root.addPreference(credStoreCat); 238 credStoreCat.addPreference(mCstorHelper.createAccessCheckBox()); 239 credStoreCat.addPreference(mCstorHelper.createSetPasswordPreference()); 240 credStoreCat.addPreference(mCstorHelper.createResetPreference()); 241 242 return root; 243 } 244 245 @Override 246 protected void onResume() { 247 super.onResume(); 248 249 boolean patternExists = mLockPatternUtils.savedPatternExists(); 250 mLockEnabled.setEnabled(patternExists); 251 mVisiblePattern.setEnabled(patternExists); 252 mTactileFeedback.setEnabled(patternExists); 253 254 mLockEnabled.setChecked(mLockPatternUtils.isLockPatternEnabled()); 255 mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled()); 256 mTactileFeedback.setChecked(mLockPatternUtils.isTactileFeedbackEnabled()); 257 258 int chooseStringRes = mLockPatternUtils.savedPatternExists() ? 259 R.string.lockpattern_settings_change_lock_pattern : 260 R.string.lockpattern_settings_choose_lock_pattern; 261 mChoosePattern.setTitle(chooseStringRes); 262 263 mShowPassword 264 .setChecked(Settings.System.getInt(getContentResolver(), 265 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0); 266 } 267 268 @Override 269 public void onStop() { 270 if (mUseLocationDialog != null && mUseLocationDialog.isShowing()) { 271 mUseLocationDialog.dismiss(); 272 } 273 mUseLocationDialog = null; 274 super.onStop(); 275 } 276 277 @Override 278 public void onSaveInstanceState(Bundle icicle) { 279 if (mUseLocationDialog != null && mUseLocationDialog.isShowing()) { 280 icicle.putBoolean(KEY_DONE_USE_LOCATION, false); 281 } 282 super.onSaveInstanceState(icicle); 283 } 284 285 @Override 286 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, 287 Preference preference) { 288 final String key = preference.getKey(); 289 290 if (KEY_LOCK_ENABLED.equals(key)) { 291 mLockPatternUtils.setLockPatternEnabled(isToggled(preference)); 292 } else if (KEY_VISIBLE_PATTERN.equals(key)) { 293 mLockPatternUtils.setVisiblePatternEnabled(isToggled(preference)); 294 } else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) { 295 mLockPatternUtils.setTactileFeedbackEnabled(isToggled(preference)); 296 } else if (preference == mShowPassword) { 297 Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 298 mShowPassword.isChecked() ? 1 : 0); 299 } else if (preference == mNetwork) { 300 Settings.Secure.setLocationProviderEnabled(getContentResolver(), 301 LocationManager.NETWORK_PROVIDER, mNetwork.isChecked()); 302 } else if (preference == mGps) { 303 boolean enabled = mGps.isChecked(); 304 Settings.Secure.setLocationProviderEnabled(getContentResolver(), 305 LocationManager.GPS_PROVIDER, enabled); 306 mAssistedGps.setEnabled(enabled); 307 } else if (preference == mAssistedGps) { 308 Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSISTED_GPS_ENABLED, 309 mAssistedGps.isChecked() ? 1 : 0); 310 } else if (preference == mUseLocation) { 311 //normally called on the toggle click 312 if (mUseLocation.isChecked()) { 313 showUseLocationDialog(false); 314 } else { 315 updateUseLocation(); 316 } 317 } 318 319 return false; 320 } 321 322 private void showPrivacyPolicy() { 323 Intent intent = new Intent("android.settings.TERMS"); 324 startActivity(intent); 325 } 326 327 private void showUseLocationDialog(boolean force) { 328 // Show a warning to the user that location data will be shared 329 mOkClicked = false; 330 if (force) { 331 mUseLocation.setChecked(true); 332 } 333 334 CharSequence msg = getResources().getText(R.string.use_location_warning_message); 335 mUseLocationDialog = new AlertDialog.Builder(this).setMessage(msg) 336 .setTitle(R.string.use_location_title) 337 .setIcon(android.R.drawable.ic_dialog_alert) 338 .setPositiveButton(R.string.agree, this) 339 .setNegativeButton(R.string.disagree, this) 340 .show(); 341 ((TextView)mUseLocationDialog.findViewById(android.R.id.message)) 342 .setMovementMethod(LinkMovementMethod.getInstance()); 343 mUseLocationDialog.setOnDismissListener(this); 344 } 345 346 /* 347 * Creates toggles for each available location provider 348 */ 349 private void updateToggles() { 350 ContentResolver res = getContentResolver(); 351 boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled( 352 res, LocationManager.GPS_PROVIDER); 353 mNetwork.setChecked(Settings.Secure.isLocationProviderEnabled( 354 res, LocationManager.NETWORK_PROVIDER)); 355 mGps.setChecked(gpsEnabled); 356 mAssistedGps.setChecked(Settings.Secure.getInt(res, 357 Settings.Secure.ASSISTED_GPS_ENABLED, 2) == 1); 358 mAssistedGps.setEnabled(gpsEnabled); 359 mUseLocation.setChecked(Settings.Secure.getInt(res, 360 Settings.Secure.USE_LOCATION_FOR_SERVICES, 2) == 1); 361 } 362 363 private boolean isToggled(Preference pref) { 364 return ((CheckBoxPreference) pref).isChecked(); 365 } 366 367 private void updateUseLocation() { 368 boolean use = mUseLocation.isChecked(); 369 Settings.Secure.putInt(getContentResolver(), 370 Settings.Secure.USE_LOCATION_FOR_SERVICES, use ? 1 : 0); 371 } 372 373 374 /** 375 * For the user to disable keyguard, we first make them verify their 376 * existing pattern. 377 */ 378 private class LockEnabledPref extends CheckBoxPreference { 379 380 public LockEnabledPref(Context context) { 381 super(context); 382 } 383 384 @Override 385 protected void onClick() { 386 if (mLockPatternUtils.savedPatternExists() && isChecked()) { 387 confirmPatternThenDisableAndClear(); 388 } else { 389 super.onClick(); 390 } 391 } 392 } 393 394 /** 395 * Launch screen to confirm the existing lock pattern. 396 * @see #onActivityResult(int, int, android.content.Intent) 397 */ 398 private void confirmPatternThenDisableAndClear() { 399 final Intent intent = new Intent(); 400 intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern"); 401 startActivityForResult(intent, CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE); 402 } 403 404 /** 405 * @see #confirmPatternThenDisableAndClear 406 */ 407 @Override 408 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 409 super.onActivityResult(requestCode, resultCode, data); 410 411 final boolean resultOk = resultCode == Activity.RESULT_OK; 412 413 if ((requestCode == CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE) 414 && resultOk) { 415 mLockPatternUtils.setLockPatternEnabled(false); 416 mLockPatternUtils.saveLockPattern(null); 417 } 418 } 419 420 public void onClick(DialogInterface dialog, int which) { 421 if (which == DialogInterface.BUTTON_POSITIVE) { 422 //updateProviders(); 423 mOkClicked = true; 424 } else { 425 // Reset the toggle 426 mUseLocation.setChecked(false); 427 } 428 updateUseLocation(); 429 } 430 431 public void onDismiss(DialogInterface dialog) { 432 // Assuming that onClick gets called first 433 if (!mOkClicked) { 434 mUseLocation.setChecked(false); 435 } 436 } 437 438 @Override 439 protected Dialog onCreateDialog (int id) { 440 switch (id) { 441 case CSTOR_INIT_DIALOG: 442 case CSTOR_CHANGE_PASSWORD_DIALOG: 443 return mCstorHelper.createSetPasswordDialog(id); 444 445 case CSTOR_UNLOCK_DIALOG: 446 return mCstorHelper.createUnlockDialog(); 447 448 case CSTOR_RESET_DIALOG: 449 return mCstorHelper.createResetDialog(); 450 451 case CSTOR_NAME_CREDENTIAL_DIALOG: 452 return mCstorHelper.createNameCredentialDialog(); 453 454 default: 455 return null; 456 } 457 } 458 459 private class CstorHelper implements DialogInterface.OnClickListener, 460 DialogInterface.OnDismissListener, 461 DialogInterface.OnCancelListener { 462 private Keystore mKeystore = Keystore.getInstance(); 463 private View mView; 464 private int mDialogId; 465 private boolean mConfirm = true; 466 467 private CheckBoxPreference mAccessCheckBox; 468 private Preference mResetButton; 469 470 private Intent mSpecialIntent; 471 private CstorAddCredentialHelper mCstorAddCredentialHelper; 472 473 void handleCstorIntents(Intent intent) { 474 if (intent == null) return; 475 String action = intent.getAction(); 476 477 if (ACTION_ADD_CREDENTIAL.equals(action)) { 478 mCstorAddCredentialHelper = new CstorAddCredentialHelper(intent); 479 showDialog(CSTOR_NAME_CREDENTIAL_DIALOG); 480 } else if (ACTION_UNLOCK_CREDENTIAL_STORAGE.equals(action)) { 481 mSpecialIntent = intent; 482 showDialog(mCstorHelper.isCstorInitialized() 483 ? CSTOR_UNLOCK_DIALOG 484 : CSTOR_INIT_DIALOG); 485 } 486 } 487 488 private boolean isCstorUnlocked() { 489 return (mKeystore.getState() == Keystore.UNLOCKED); 490 } 491 492 private boolean isCstorInitialized() { 493 return (mKeystore.getState() != Keystore.UNINITIALIZED); 494 } 495 496 private void lockCstor() { 497 mKeystore.lock(); 498 mAccessCheckBox.setChecked(false); 499 } 500 501 private int unlockCstor(String passwd) { 502 int ret = mKeystore.unlock(passwd); 503 if (ret == -1) resetCstor(); 504 if (ret == 0) { 505 Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled, 506 Toast.LENGTH_SHORT).show(); 507 } 508 return ret; 509 } 510 511 private int changeCstorPassword(String oldPasswd, String newPasswd) { 512 int ret = mKeystore.changePassword(oldPasswd, newPasswd); 513 if (ret == -1) resetCstor(); 514 return ret; 515 } 516 517 private void initCstor(String passwd) { 518 mKeystore.setPassword(passwd); 519 enablePreferences(true); 520 mAccessCheckBox.setChecked(true); 521 Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled, 522 Toast.LENGTH_SHORT).show(); 523 } 524 525 private void resetCstor() { 526 mKeystore.reset(); 527 enablePreferences(false); 528 mAccessCheckBox.setChecked(false); 529 } 530 531 public void onCancel(DialogInterface dialog) { 532 if (mCstorAddCredentialHelper != null) { 533 // release the object here so that it doesn't get triggerred in 534 // onDismiss() 535 mCstorAddCredentialHelper = null; 536 finish(); 537 } 538 } 539 540 public void onClick(DialogInterface dialog, int which) { 541 if (which == DialogInterface.BUTTON_NEGATIVE) { 542 onCancel(dialog); 543 return; 544 } 545 546 switch (mDialogId) { 547 case CSTOR_INIT_DIALOG: 548 case CSTOR_CHANGE_PASSWORD_DIALOG: 549 mConfirm = checkPasswords((Dialog) dialog); 550 break; 551 552 case CSTOR_UNLOCK_DIALOG: 553 mConfirm = checkUnlockPassword((Dialog) dialog); 554 break; 555 556 case CSTOR_RESET_DIALOG: 557 resetCstor(); 558 break; 559 560 case CSTOR_NAME_CREDENTIAL_DIALOG: 561 mConfirm = checkAddCredential(); 562 break; 563 } 564 } 565 566 public void onDismiss(DialogInterface dialog) { 567 if (!mConfirm) { 568 mConfirm = true; 569 showDialog(mDialogId); 570 } else { 571 removeDialog(mDialogId); 572 573 if (mDialogId == CSTOR_UNLOCK_DIALOG) { 574 mAccessCheckBox.setChecked(isCstorUnlocked()); 575 } 576 577 if (mCstorAddCredentialHelper != null) { 578 if (!isCstorInitialized()) { 579 showDialog(CSTOR_INIT_DIALOG); 580 } else if (!isCstorUnlocked()) { 581 showDialog(CSTOR_UNLOCK_DIALOG); 582 } else { 583 String formatString = 584 getString(R.string.cstor_is_added); 585 String message = String.format(formatString, 586 mCstorAddCredentialHelper.getName()); 587 Toast.makeText(SecuritySettings.this, message, 588 Toast.LENGTH_SHORT).show(); 589 finish(); 590 } 591 } else if (mSpecialIntent != null) { 592 finish(); 593 } 594 } 595 } 596 597 private void showResetWarning(int count) { 598 TextView v = showError(count <= 3 599 ? R.string.cstor_password_error_reset_warning 600 : R.string.cstor_password_error); 601 if (count <= 3) { 602 if (count == 1) { 603 v.setText(R.string.cstor_password_error_reset_warning); 604 } else { 605 String format = getString( 606 R.string.cstor_password_error_reset_warning_plural); 607 v.setText(String.format(format, count)); 608 } 609 } 610 } 611 612 private boolean checkAddCredential() { 613 hideError(); 614 615 String name = getText(R.id.cstor_credential_name); 616 if (TextUtils.isEmpty(name)) { 617 showError(R.string.cstor_name_empty_error); 618 return false; 619 } 620 621 for (int i = 0, len = name.length(); i < len; i++) { 622 if (!Character.isLetterOrDigit(name.charAt(i))) { 623 showError(R.string.cstor_name_char_error); 624 return false; 625 } 626 } 627 628 mCstorAddCredentialHelper.setName(name); 629 630 if (mCstorAddCredentialHelper.isPkcs12Keystore()) { 631 String password = getText(R.id.cstor_credential_password); 632 if (TextUtils.isEmpty(password)) { 633 showError(R.string.cstor_password_empty_error); 634 return false; 635 } 636 637 mCstorAddCredentialHelper.setPassword(password); 638 } 639 640 if (mCstorAddCredentialHelper.saveToStorage() < 0) { 641 if (mCstorAddCredentialHelper.isPkcs12Keystore()) { 642 showError(R.string.cstor_password_error); 643 } else { 644 showError(R.string.cstor_storage_error); 645 } 646 return false; 647 } 648 649 return true; 650 } 651 652 // returns true if the password is long enough and does not contain 653 // characters that we don't like 654 private boolean verifyPassword(String passwd) { 655 if (passwd == null) { 656 showError(R.string.cstor_passwords_empty_error); 657 return false; 658 } else if ((passwd.length() < CSTOR_MIN_PASSWORD_LENGTH) 659 || passwd.contains(" ")) { 660 showError(R.string.cstor_password_verification_error); 661 return false; 662 } else { 663 return true; 664 } 665 } 666 667 // returns true if the password is ok 668 private boolean checkUnlockPassword(Dialog d) { 669 hideError(); 670 671 String passwd = getText(R.id.cstor_password); 672 if (TextUtils.isEmpty(passwd)) { 673 showError(R.string.cstor_password_empty_error); 674 return false; 675 } 676 677 int count = unlockCstor(passwd); 678 if (count > 0) { 679 showResetWarning(count); 680 return false; 681 } else { 682 // done or reset 683 return true; 684 } 685 } 686 687 // returns true if the passwords are ok 688 private boolean checkPasswords(Dialog d) { 689 hideError(); 690 691 String oldPasswd = getText(R.id.cstor_old_password); 692 String newPasswd = getText(R.id.cstor_new_password); 693 String confirmPasswd = getText(R.id.cstor_confirm_password); 694 695 if ((mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG) 696 && TextUtils.isEmpty(oldPasswd)) { 697 showError(R.string.cstor_password_empty_error); 698 return false; 699 } 700 701 if (TextUtils.isEmpty(newPasswd) 702 && TextUtils.isEmpty(confirmPasswd)) { 703 showError(R.string.cstor_passwords_empty_error); 704 return false; 705 } 706 707 if (!verifyPassword(newPasswd)) { 708 return false; 709 } else if (!newPasswd.equals(confirmPasswd)) { 710 showError(R.string.cstor_passwords_error); 711 return false; 712 } 713 714 if (mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG) { 715 int count = changeCstorPassword(oldPasswd, newPasswd); 716 if (count > 0) { 717 showResetWarning(count); 718 return false; 719 } else { 720 // done or reset 721 return true; 722 } 723 } else { 724 initCstor(newPasswd); 725 return true; 726 } 727 } 728 729 private TextView showError(int messageId) { 730 TextView v = (TextView) mView.findViewById(R.id.cstor_error); 731 v.setText(messageId); 732 if (v != null) v.setVisibility(View.VISIBLE); 733 return v; 734 } 735 736 private void hide(int viewId) { 737 View v = mView.findViewById(viewId); 738 if (v != null) v.setVisibility(View.GONE); 739 } 740 741 private void hideError() { 742 hide(R.id.cstor_error); 743 } 744 745 private String getText(int viewId) { 746 return ((TextView) mView.findViewById(viewId)).getText().toString(); 747 } 748 749 private void setText(int viewId, String text) { 750 TextView v = (TextView) mView.findViewById(viewId); 751 if (v != null) v.setText(text); 752 } 753 754 private void setText(int viewId, int textId) { 755 TextView v = (TextView) mView.findViewById(viewId); 756 if (v != null) v.setText(textId); 757 } 758 759 private void enablePreferences(boolean enabled) { 760 mAccessCheckBox.setEnabled(enabled); 761 mResetButton.setEnabled(enabled); 762 } 763 764 private Preference createAccessCheckBox() { 765 CheckBoxPreference pref = new CheckBoxPreference( 766 SecuritySettings.this); 767 pref.setTitle(R.string.cstor_access_title); 768 pref.setSummary(R.string.cstor_access_summary); 769 pref.setChecked(isCstorUnlocked()); 770 pref.setOnPreferenceChangeListener( 771 new Preference.OnPreferenceChangeListener() { 772 public boolean onPreferenceChange( 773 Preference pref, Object value) { 774 if (((Boolean) value)) { 775 showDialog(isCstorInitialized() 776 ? CSTOR_UNLOCK_DIALOG 777 : CSTOR_INIT_DIALOG); 778 } else { 779 lockCstor(); 780 } 781 return true; 782 } 783 }); 784 pref.setEnabled(isCstorInitialized()); 785 mAccessCheckBox = pref; 786 return pref; 787 } 788 789 private Preference createSetPasswordPreference() { 790 Preference pref = new Preference(SecuritySettings.this); 791 pref.setTitle(R.string.cstor_set_passwd_title); 792 pref.setSummary(R.string.cstor_set_passwd_summary); 793 pref.setOnPreferenceClickListener( 794 new Preference.OnPreferenceClickListener() { 795 public boolean onPreferenceClick(Preference pref) { 796 showDialog(isCstorInitialized() 797 ? CSTOR_CHANGE_PASSWORD_DIALOG 798 : CSTOR_INIT_DIALOG); 799 return true; 800 } 801 }); 802 return pref; 803 } 804 805 private Preference createResetPreference() { 806 Preference pref = new Preference(SecuritySettings.this); 807 pref.setTitle(R.string.cstor_reset_title); 808 pref.setSummary(R.string.cstor_reset_summary); 809 pref.setOnPreferenceClickListener( 810 new Preference.OnPreferenceClickListener() { 811 public boolean onPreferenceClick(Preference pref) { 812 showDialog(CSTOR_RESET_DIALOG); 813 return true; 814 } 815 }); 816 pref.setEnabled(isCstorInitialized()); 817 mResetButton = pref; 818 return pref; 819 } 820 821 private Dialog createUnlockDialog() { 822 mDialogId = CSTOR_UNLOCK_DIALOG; 823 mView = View.inflate(SecuritySettings.this, 824 R.layout.cstor_unlock_dialog_view, null); 825 hideError(); 826 827 // show extra hint only when the action comes from outside 828 if ((mSpecialIntent == null) 829 && (mCstorAddCredentialHelper == null)) { 830 hide(R.id.cstor_access_dialog_hint_from_action); 831 } 832 833 Dialog d = new AlertDialog.Builder(SecuritySettings.this) 834 .setView(mView) 835 .setTitle(R.string.cstor_access_dialog_title) 836 .setPositiveButton(android.R.string.ok, this) 837 .setNegativeButton(android.R.string.cancel, this) 838 .setOnCancelListener(this) 839 .create(); 840 d.setOnDismissListener(this); 841 return d; 842 } 843 844 private Dialog createSetPasswordDialog(int id) { 845 mDialogId = id; 846 mView = View.inflate(SecuritySettings.this, 847 R.layout.cstor_set_password_dialog_view, null); 848 hideError(); 849 850 // show extra hint only when the action comes from outside 851 if ((mSpecialIntent != null) 852 || (mCstorAddCredentialHelper != null)) { 853 setText(R.id.cstor_first_time_hint, 854 R.string.cstor_first_time_hint_from_action); 855 } 856 857 switch (id) { 858 case CSTOR_INIT_DIALOG: 859 mView.findViewById(R.id.cstor_old_password_block) 860 .setVisibility(View.GONE); 861 break; 862 863 case CSTOR_CHANGE_PASSWORD_DIALOG: 864 mView.findViewById(R.id.cstor_first_time_hint) 865 .setVisibility(View.GONE); 866 break; 867 868 default: 869 throw new RuntimeException( 870 "Unknown dialog id: " + mDialogId); 871 } 872 873 Dialog d = new AlertDialog.Builder(SecuritySettings.this) 874 .setView(mView) 875 .setTitle(R.string.cstor_set_passwd_dialog_title) 876 .setPositiveButton(android.R.string.ok, this) 877 .setNegativeButton(android.R.string.cancel, this) 878 .setOnCancelListener(this) 879 .create(); 880 d.setOnDismissListener(this); 881 return d; 882 } 883 884 private Dialog createResetDialog() { 885 mDialogId = CSTOR_RESET_DIALOG; 886 return new AlertDialog.Builder(SecuritySettings.this) 887 .setTitle(android.R.string.dialog_alert_title) 888 .setIcon(android.R.drawable.ic_dialog_alert) 889 .setMessage(R.string.cstor_reset_hint) 890 .setPositiveButton(getString(android.R.string.ok), this) 891 .setNegativeButton(getString(android.R.string.cancel), this) 892 .create(); 893 } 894 895 private Dialog createNameCredentialDialog() { 896 mDialogId = CSTOR_NAME_CREDENTIAL_DIALOG; 897 mView = View.inflate(SecuritySettings.this, 898 R.layout.cstor_name_credential_dialog_view, null); 899 hideError(); 900 if (!mCstorAddCredentialHelper.isPkcs12Keystore()) { 901 hide(R.id.cstor_credential_password_container); 902 } 903 904 setText(R.id.cstor_credential_name_title, 905 R.string.cstor_credential_name); 906 setText(R.id.cstor_credential_info_title, 907 R.string.cstor_credential_info); 908 setText(R.id.cstor_credential_info, 909 mCstorAddCredentialHelper.getDescription().toString()); 910 911 Dialog d = new AlertDialog.Builder(SecuritySettings.this) 912 .setView(mView) 913 .setTitle(R.string.cstor_name_credential_dialog_title) 914 .setPositiveButton(android.R.string.ok, this) 915 .setNegativeButton(android.R.string.cancel, this) 916 .setOnCancelListener(this) 917 .create(); 918 d.setOnDismissListener(this); 919 return d; 920 } 921 } 922 923 private class CstorAddCredentialHelper { 924 private String mTypeName; 925 private List<byte[]> mItemList; 926 private List<String> mNamespaceList; 927 private String mDescription; 928 private String mName; 929 private String mPassword; 930 931 CstorAddCredentialHelper(Intent intent) { 932 parse(intent); 933 } 934 935 String getTypeName() { 936 return mTypeName; 937 } 938 939 boolean isPkcs12Keystore() { 940 return CertTool.TITLE_PKCS12_KEYSTORE.equals(mTypeName); 941 } 942 943 CharSequence getDescription() { 944 return Html.fromHtml(mDescription); 945 } 946 947 void setName(String name) { 948 mName = name; 949 } 950 951 String getName() { 952 return mName; 953 } 954 955 void setPassword(String password) { 956 mPassword = password; 957 } 958 959 String getPassword() { 960 return mPassword; 961 } 962 963 int saveToStorage() { 964 if (isPkcs12Keystore()) { 965 return CertTool.getInstance().addPkcs12Keystore( 966 mItemList.get(0), mPassword, mName); 967 } else { 968 Keystore ks = Keystore.getInstance(); 969 for (int i = 0, count = mItemList.size(); i < count; i++) { 970 byte[] blob = mItemList.get(i); 971 int ret = ks.put(mNamespaceList.get(i), mName, 972 new String(blob)); 973 if (ret < 0) return ret; 974 } 975 } 976 return 0; 977 } 978 979 private void parse(Intent intent) { 980 mTypeName = intent.getStringExtra(KEY_CSTOR_TYPE_NAME); 981 mItemList = new ArrayList<byte[]>(); 982 mNamespaceList = new ArrayList<String>(); 983 for (int i = 0; ; i++) { 984 byte[] blob = intent.getByteArrayExtra(KEY_CSTOR_ITEM + i); 985 if (blob == null) break; 986 mItemList.add(blob); 987 mNamespaceList.add(intent.getStringExtra( 988 KEY_CSTOR_NAMESPACE + i)); 989 } 990 991 // build description string 992 StringBuilder sb = new StringBuilder(); 993 for (int i = 0; ; i++) { 994 String s = intent.getStringExtra(KEY_CSTOR_DESCRIPTION + i); 995 if (s == null) break; 996 sb.append(s).append("<br>"); 997 } 998 mDescription = sb.toString(); 999 } 1000 } 1001} 1002