diff options
author | Hung-ying Tyan <tyanh@google.com> | 2009-07-02 00:26:46 +0800 |
---|---|---|
committer | Hung-ying Tyan <tyanh@google.com> | 2009-07-03 23:00:53 +0800 |
commit | 7031ab0d756327496ac3ce1e082b53c94be2f3b1 (patch) | |
tree | 085e3a09725957e891c25e97079ea7748091665a /src/com | |
parent | 132b21440b1b930322fc129a504afa6107835f8e (diff) | |
download | packages_apps_settings-7031ab0d756327496ac3ce1e082b53c94be2f3b1.zip packages_apps_settings-7031ab0d756327496ac3ce1e082b53c94be2f3b1.tar.gz packages_apps_settings-7031ab0d756327496ac3ce1e082b53c94be2f3b1.tar.bz2 |
Add credential storage settings.
* Changes
+ Initial implementation of credential storage settings.
+ Use alert icon on delete and reconnect dialogs in VpnSettings.
(piggy-backed)
Patch Set 12:
+ Add password length and no-space verification.
+ Simplify dialog view xml files.
Diffstat (limited to 'src/com')
-rw-r--r-- | src/com/android/settings/SecuritySettings.java | 538 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnSettings.java | 2 |
2 files changed, 533 insertions, 7 deletions
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index e0d0cc1..b5efaad 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -30,18 +30,26 @@ import android.database.Cursor; import android.location.LocationManager; import android.os.Bundle; import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.provider.Settings; +import android.security.Keystore; +import android.text.Html; +import android.text.TextUtils; import android.text.method.LinkMovementMethod; +import android.view.View; import android.widget.TextView; +import android.widget.Toast; import com.android.internal.widget.LockPatternUtils; import android.telephony.TelephonyManager; +import java.util.ArrayList; +import java.util.List; import java.util.Observable; import java.util.Observer; @@ -52,7 +60,7 @@ public class SecuritySettings extends PreferenceActivity implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { // Lock Settings - + private static final String KEY_LOCK_ENABLED = "lockenabled"; private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback"; @@ -65,12 +73,31 @@ public class SecuritySettings extends PreferenceActivity implements private Preference mChoosePattern; private CheckBoxPreference mShowPassword; - + // Location Settings private static final String LOCATION_CATEGORY = "location_category"; private static final String LOCATION_NETWORK = "location_network"; private static final String LOCATION_GPS = "location_gps"; + // Credential storage + private static final String ACTION_ADD_CREDENTIAL = + "android.security.ADD_CREDENTIAL"; + private static final String ACTION_UNLOCK_CREDENTIAL_STORAGE = + "android.security.UNLOCK_CREDENTIAL_STORAGE"; + private static final String KEY_CSTOR_TYPE_NAME = "typeName"; + private static final String KEY_CSTOR_ITEM = "item"; + private static final String KEY_CSTOR_NAMESPACE = "namespace"; + private static final String KEY_CSTOR_DESCRIPTION = "description"; + private static final int CSTOR_MIN_PASSWORD_LENGTH = 8; + + private static final int CSTOR_INIT_DIALOG = 1; + private static final int CSTOR_CHANGE_PASSWORD_DIALOG = 2; + private static final int CSTOR_UNLOCK_DIALOG = 3; + private static final int CSTOR_RESET_DIALOG = 4; + private static final int CSTOR_NAME_CREDENTIAL_DIALOG = 5; + + private CstorHelper mCstorHelper = new CstorHelper(); + // Vendor specific private static final String GSETTINGS_PROVIDER = "com.google.android.providers.settings"; private static final String USE_LOCATION = "use_location"; @@ -128,6 +155,8 @@ public class SecuritySettings extends PreferenceActivity implements if (getIntent().getBooleanExtra("SHOW_USE_LOCATION", false) && !doneUseLocation) { showUseLocationDialog(true); } + + mCstorHelper.handleCstorIntents(getIntent()); } private PreferenceScreen createPreferenceHierarchy() { @@ -165,7 +194,7 @@ public class SecuritySettings extends PreferenceActivity implements mChoosePattern = getPreferenceManager().createPreferenceScreen(this); mChoosePattern.setIntent(intent); inlinePrefCat.addPreference(mChoosePattern); - + int activePhoneType = TelephonyManager.getDefault().getPhoneType(); // do not display SIM lock for CDMA phone @@ -178,7 +207,7 @@ public class SecuritySettings extends PreferenceActivity implements intent = new Intent(); intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings"); simLockPreferences.setIntent(intent); - + PreferenceCategory simLockCat = new PreferenceCategory(this); simLockCat.setTitle(R.string.sim_lock_settings_title); root.addPreference(simLockCat); @@ -189,14 +218,22 @@ public class SecuritySettings extends PreferenceActivity implements PreferenceCategory passwordsCat = new PreferenceCategory(this); passwordsCat.setTitle(R.string.security_passwords_title); root.addPreference(passwordsCat); - + CheckBoxPreference showPassword = mShowPassword = new CheckBoxPreference(this); showPassword.setKey("show_password"); showPassword.setTitle(R.string.show_password); showPassword.setSummary(R.string.show_password_summary); showPassword.setPersistent(false); passwordsCat.addPreference(showPassword); - + + // Credential storage + PreferenceCategory credStoreCat = new PreferenceCategory(this); + credStoreCat.setTitle(R.string.cstor_settings_category); + root.addPreference(credStoreCat); + credStoreCat.addPreference(mCstorHelper.createAccessCheckBox()); + credStoreCat.addPreference(mCstorHelper.createSetPasswordPreference()); + credStoreCat.addPreference(mCstorHelper.createResetPreference()); + return root; } @@ -217,7 +254,7 @@ public class SecuritySettings extends PreferenceActivity implements R.string.lockpattern_settings_change_lock_pattern : R.string.lockpattern_settings_choose_lock_pattern; mChoosePattern.setTitle(chooseStringRes); - + mShowPassword .setChecked(Settings.System.getInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1) != 0); @@ -383,4 +420,491 @@ public class SecuritySettings extends PreferenceActivity implements mUseLocation.setChecked(false); } } + + @Override + protected Dialog onCreateDialog (int id) { + switch (id) { + case CSTOR_INIT_DIALOG: + case CSTOR_CHANGE_PASSWORD_DIALOG: + return mCstorHelper.createSetPasswordDialog(id); + + case CSTOR_UNLOCK_DIALOG: + return mCstorHelper.createUnlockDialog(); + + case CSTOR_RESET_DIALOG: + return mCstorHelper.createResetDialog(); + + case CSTOR_NAME_CREDENTIAL_DIALOG: + return mCstorHelper.createNameCredentialDialog(); + + default: + return null; + } + } + + private class CstorHelper implements + DialogInterface.OnClickListener, DialogInterface.OnDismissListener { + private Keystore mKeystore = Keystore.getInstance(); + private View mView; + private int mDialogId; + private boolean mConfirm = true; + + private CheckBoxPreference mAccessCheckBox; + private Preference mResetButton; + + private Intent mSpecialIntent; + private CstorAddCredentialHelper mCstorAddCredentialHelper; + + void handleCstorIntents(Intent intent) { + if (intent == null) return; + String action = intent.getAction(); + + if (ACTION_ADD_CREDENTIAL.equals(action)) { + mCstorAddCredentialHelper = new CstorAddCredentialHelper(intent); + showDialog(CSTOR_NAME_CREDENTIAL_DIALOG); + } else if (ACTION_UNLOCK_CREDENTIAL_STORAGE.equals(action)) { + mSpecialIntent = intent; + showDialog(mCstorHelper.isCstorInitialized() + ? CSTOR_UNLOCK_DIALOG + : CSTOR_INIT_DIALOG); + } + } + + private boolean isCstorUnlocked() { + return (mKeystore.getState() == Keystore.UNLOCKED); + } + + private boolean isCstorInitialized() { + return (mKeystore.getState() != Keystore.UNINITIALIZED); + } + + private void lockCstor() { + mKeystore.lock(); + mAccessCheckBox.setChecked(false); + } + + private int unlockCstor(String passwd) { + int ret = mKeystore.unlock(passwd); + if (ret == -1) resetCstor(); + if (ret == 0) { + Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled, + Toast.LENGTH_SHORT).show(); + } + return ret; + } + + private int changeCstorPassword(String oldPasswd, String newPasswd) { + int ret = mKeystore.changePassword(oldPasswd, newPasswd); + if (ret == -1) resetCstor(); + return ret; + } + + private void initCstor(String passwd) { + mKeystore.setPassword(passwd); + enablePreferences(true); + mAccessCheckBox.setChecked(true); + Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled, + Toast.LENGTH_SHORT).show(); + } + + private void resetCstor() { + mKeystore.reset(); + enablePreferences(false); + mAccessCheckBox.setChecked(false); + } + + private void addCredential() { + String message = String.format(getString(R.string.cstor_is_added), + mCstorAddCredentialHelper.getName()); + Toast.makeText(SecuritySettings.this, message, Toast.LENGTH_SHORT) + .show(); + } + + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_NEGATIVE) { + if (mCstorAddCredentialHelper != null) finish(); + return; + } + + switch (mDialogId) { + case CSTOR_INIT_DIALOG: + case CSTOR_CHANGE_PASSWORD_DIALOG: + mConfirm = checkPasswords((Dialog) dialog); + break; + + case CSTOR_UNLOCK_DIALOG: + mConfirm = checkUnlockPassword((Dialog) dialog); + break; + + case CSTOR_RESET_DIALOG: + resetCstor(); + break; + + case CSTOR_NAME_CREDENTIAL_DIALOG: + mConfirm = checkAddCredential(); + break; + } + } + + public void onDismiss(DialogInterface dialog) { + if (!mConfirm) { + mConfirm = true; + showDialog(mDialogId); + } else { + removeDialog(mDialogId); + + if (mCstorAddCredentialHelper != null) { + if (!isCstorInitialized()) { + showDialog(CSTOR_INIT_DIALOG); + } else if (!isCstorUnlocked()) { + showDialog(CSTOR_UNLOCK_DIALOG); + } else { + addCredential(); + finish(); + } + } else if (mSpecialIntent != null) { + finish(); + } + } + } + + private void showResetWarning(int count) { + TextView v = showError(count <= 3 + ? R.string.cstor_password_error_reset_warning + : R.string.cstor_password_error); + if (count <= 3) { + if (count == 1) { + v.setText(getString( + R.string.cstor_password_error_reset_warning)); + } else { + String format = getString( + R.string.cstor_password_error_reset_warning_plural); + v.setText(String.format(format, count)); + } + } + } + + private boolean checkAddCredential() { + hideError(); + + String name = getText(R.id.cstor_credential_name); + if (TextUtils.isEmpty(name)) { + showError(R.string.cstor_name_empty_error); + return false; + } + + for (int i = 0, len = name.length(); i < len; i++) { + if (!Character.isLetterOrDigit(name.charAt(i))) { + showError(R.string.cstor_name_char_error); + return false; + } + } + + mCstorAddCredentialHelper.setName(name); + return true; + } + + // returns true if the password is long enough and does not contain + // characters that we don't like + private boolean verifyPassword(String passwd) { + if (passwd == null) { + showError(R.string.cstor_passwords_empty_error); + return false; + } else if ((passwd.length() < CSTOR_MIN_PASSWORD_LENGTH) + || passwd.contains(" ")) { + showError(R.string.cstor_password_verification_error); + return false; + } else { + return true; + } + } + + // returns true if the password is ok + private boolean checkUnlockPassword(Dialog d) { + hideError(); + + String passwd = getText(R.id.cstor_password); + if (TextUtils.isEmpty(passwd)) { + showError(R.string.cstor_password_empty_error); + return false; + } + + int count = unlockCstor(passwd); + if (count > 0) { + showResetWarning(count); + return false; + } else { + // done or reset + return true; + } + } + + // returns true if the passwords are ok + private boolean checkPasswords(Dialog d) { + hideError(); + + String oldPasswd = getText(R.id.cstor_old_password); + String newPasswd = getText(R.id.cstor_new_password); + String confirmPasswd = getText(R.id.cstor_confirm_password); + + if ((mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG) + && TextUtils.isEmpty(oldPasswd)) { + showError(R.string.cstor_password_empty_error); + return false; + } + + if (TextUtils.isEmpty(newPasswd) + && TextUtils.isEmpty(confirmPasswd)) { + showError(R.string.cstor_passwords_empty_error); + return false; + } + + if (!verifyPassword(newPasswd)) { + return false; + } else if (!newPasswd.equals(confirmPasswd)) { + showError(R.string.cstor_passwords_error); + return false; + } + + if (mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG) { + int count = changeCstorPassword(oldPasswd, newPasswd); + if (count > 0) { + showResetWarning(count); + return false; + } else { + // done or reset + return true; + } + } else { + initCstor(newPasswd); + return true; + } + } + + private TextView showError(int messageId) { + TextView v = (TextView) mView.findViewById(R.id.cstor_error); + v.setText(messageId); + if (v != null) v.setVisibility(View.VISIBLE); + return v; + } + + private void hideError() { + View v = mView.findViewById(R.id.cstor_error); + if (v != null) v.setVisibility(View.GONE); + } + + private String getText(int viewId) { + return ((TextView) mView.findViewById(viewId)).getText().toString(); + } + + private void setText(int viewId, String text) { + TextView v = (TextView) mView.findViewById(viewId); + if (v != null) v.setText(text); + } + + private void enablePreferences(boolean enabled) { + mAccessCheckBox.setEnabled(enabled); + mResetButton.setEnabled(enabled); + } + + private Preference createAccessCheckBox() { + CheckBoxPreference pref = new CheckBoxPreference( + SecuritySettings.this); + pref.setTitle(R.string.cstor_access_title); + pref.setSummary(R.string.cstor_access_summary); + pref.setChecked(isCstorUnlocked()); + pref.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange( + Preference pref, Object value) { + if (((Boolean) value)) { + showDialog(isCstorInitialized() + ? CSTOR_UNLOCK_DIALOG + : CSTOR_INIT_DIALOG); + } else { + lockCstor(); + } + return true; + } + }); + pref.setEnabled(isCstorInitialized()); + mAccessCheckBox = pref; + return pref; + } + + private Preference createSetPasswordPreference() { + Preference pref = new Preference(SecuritySettings.this); + pref.setTitle(R.string.cstor_set_passwd_title); + pref.setSummary(R.string.cstor_set_passwd_summary); + pref.setOnPreferenceClickListener( + new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference pref) { + showDialog(isCstorInitialized() + ? CSTOR_CHANGE_PASSWORD_DIALOG + : CSTOR_INIT_DIALOG); + return true; + } + }); + return pref; + } + + private Preference createResetPreference() { + Preference pref = new Preference(SecuritySettings.this); + pref.setTitle(R.string.cstor_reset_title); + pref.setSummary(R.string.cstor_reset_summary); + pref.setOnPreferenceClickListener( + new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference pref) { + showDialog(CSTOR_RESET_DIALOG); + return true; + } + }); + pref.setEnabled(isCstorInitialized()); + mResetButton = pref; + return pref; + } + + private Dialog createUnlockDialog() { + mDialogId = CSTOR_UNLOCK_DIALOG; + mView = View.inflate(SecuritySettings.this, + R.layout.cstor_unlock_dialog_view, null); + hideError(); + + Dialog d = new AlertDialog.Builder(SecuritySettings.this) + .setView(mView) + .setTitle(R.string.cstor_access_dialog_title) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .setCancelable(false) + .create(); + d.setOnDismissListener(this); + return d; + } + + private Dialog createSetPasswordDialog(int id) { + mDialogId = id; + mView = View.inflate(SecuritySettings.this, + R.layout.cstor_set_password_dialog_view, null); + hideError(); + + switch (id) { + case CSTOR_INIT_DIALOG: + mView.findViewById(R.id.cstor_old_password_block) + .setVisibility(View.GONE); + break; + + case CSTOR_CHANGE_PASSWORD_DIALOG: + mView.findViewById(R.id.cstor_first_time_hint) + .setVisibility(View.GONE); + break; + + default: + throw new RuntimeException( + "Unknown dialog id: " + mDialogId); + } + + Dialog d = new AlertDialog.Builder(SecuritySettings.this) + .setView(mView) + .setTitle(R.string.cstor_set_passwd_dialog_title) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .setCancelable(false) + .create(); + d.setOnDismissListener(this); + return d; + } + + private Dialog createResetDialog() { + mDialogId = CSTOR_RESET_DIALOG; + return new AlertDialog.Builder(SecuritySettings.this) + .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.cstor_reset_hint) + .setPositiveButton(getString(android.R.string.ok), this) + .setNegativeButton(getString(android.R.string.cancel), this) + .create(); + } + + private Dialog createNameCredentialDialog() { + mDialogId = CSTOR_NAME_CREDENTIAL_DIALOG; + mView = View.inflate(SecuritySettings.this, + R.layout.cstor_name_credential_dialog_view, null); + hideError(); + + setText(R.id.cstor_credential_name_title, + getString(R.string.cstor_credential_name)); + setText(R.id.cstor_credential_info_title, + getString(R.string.cstor_credential_info)); + setText(R.id.cstor_credential_info, + mCstorAddCredentialHelper.getDescription().toString()); + + Dialog d = new AlertDialog.Builder(SecuritySettings.this) + .setView(mView) + .setTitle(R.string.cstor_name_credential_dialog_title) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .setCancelable(false) + .create(); + d.setOnDismissListener(this); + return d; + } + } + + private class CstorAddCredentialHelper { + private String mTypeName; + private List<byte[]> mItemList; + private List<String> mNamespaceList; + private String mDescription; + private String mName; + + CstorAddCredentialHelper(Intent intent) { + parse(intent); + } + + String getTypeName() { + return mTypeName; + } + + byte[] getItem(int i) { + return mItemList.get(i); + } + + String getNamespace(int i) { + return mNamespaceList.get(i); + } + + CharSequence getDescription() { + return Html.fromHtml(mDescription); + } + + void setName(String name) { + mName = name; + } + + String getName() { + return mName; + } + + private void parse(Intent intent) { + mTypeName = intent.getStringExtra(KEY_CSTOR_TYPE_NAME); + mItemList = new ArrayList<byte[]>(); + mNamespaceList = new ArrayList<String>(); + for (int i = 0; ; i++) { + byte[] blob = intent.getByteArrayExtra(KEY_CSTOR_ITEM + i); + if (blob == null) break; + mItemList.add(blob); + mNamespaceList.add(intent.getStringExtra( + KEY_CSTOR_NAMESPACE + i)); + } + + // build description string + StringBuilder sb = new StringBuilder(); + for (int i = 0; ; i++) { + String s = intent.getStringExtra(KEY_CSTOR_DESCRIPTION + i); + if (s == null) break; + sb.append(s).append("<br>"); + } + mDescription = sb.toString(); + } + } } diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java index 1603998..bbbe9b9 100644 --- a/src/com/android/settings/vpn/VpnSettings.java +++ b/src/com/android/settings/vpn/VpnSettings.java @@ -407,6 +407,7 @@ public class VpnSettings extends PreferenceActivity implements }; new AlertDialog.Builder(this) .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(R.string.vpn_confirm_profile_deletion) .setPositiveButton(android.R.string.ok, onClickListener) .setNegativeButton(R.string.vpn_no_button, onClickListener) @@ -539,6 +540,7 @@ public class VpnSettings extends PreferenceActivity implements private void showReconnectDialog(final VpnProfile p) { new AlertDialog.Builder(this) .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(R.string.vpn_confirm_reconnect) .setPositiveButton(R.string.vpn_yes_button, new DialogInterface.OnClickListener() { |