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