summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHung-ying Tyan <tyanh@google.com>2009-07-02 00:26:46 +0800
committerHung-ying Tyan <tyanh@google.com>2009-07-03 23:00:53 +0800
commit7031ab0d756327496ac3ce1e082b53c94be2f3b1 (patch)
tree085e3a09725957e891c25e97079ea7748091665a /src
parent132b21440b1b930322fc129a504afa6107835f8e (diff)
downloadpackages_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')
-rw-r--r--src/com/android/settings/SecuritySettings.java538
-rw-r--r--src/com/android/settings/vpn/VpnSettings.java2
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() {