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.
diff --git a/res/layout/cstor_name_credential_dialog_view.xml b/res/layout/cstor_name_credential_dialog_view.xml
new file mode 100644
index 0000000..e5ccb36
--- /dev/null
+++ b/res/layout/cstor_name_credential_dialog_view.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:orientation="vertical"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:padding="15dip">
+
+        <TextView android:id="@+id/cstor_name_credential_hint"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:textSize="@dimen/vpn_connect_normal_text_size"
+                android:text="@string/cstor_name_credential_hint"
+                android:layout_marginBottom="10sp" />
+
+        <TextView android:id="@+id/cstor_error"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:textColor="@color/red"
+                android:textStyle="bold" />
+
+        <TextView android:id="@+id/cstor_credential_name_title"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/cstor_credential_name" />
+        <EditText android:id="@+id/cstor_credential_name"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="True"/>
+
+        <TextView android:id="@+id/cstor_credential_info_title"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/cstor_credential_info" />
+        <TextView android:id="@+id/cstor_credential_info"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" />
+
+    </LinearLayout>
+</ScrollView>
diff --git a/res/layout/cstor_set_password_dialog_view.xml b/res/layout/cstor_set_password_dialog_view.xml
new file mode 100644
index 0000000..eda317a
--- /dev/null
+++ b/res/layout/cstor_set_password_dialog_view.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:orientation="vertical"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:padding="15dip">
+
+        <TextView android:id="@+id/cstor_first_time_hint"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:textSize="@dimen/vpn_connect_normal_text_size"
+                android:text="@string/cstor_first_time_hint"
+                android:layout_marginBottom="10sp" />
+
+        <TextView android:id="@+id/cstor_error"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:textColor="@color/red"
+                android:textStyle="bold"
+                android:text="@string/cstor_password_empty_error" />
+
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/cstor_old_password_block"
+                android:orientation="vertical"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                >
+            <TextView android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/cstor_old_password" />
+            <EditText android:id="@+id/cstor_old_password"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:password="True"
+                    android:singleLine="True"/>
+        </LinearLayout>
+
+        <TextView android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/cstor_new_password" />
+        <EditText android:id="@+id/cstor_new_password"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:password="True"
+                android:singleLine="True"/>
+
+        <TextView android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/cstor_confirm_password" />
+        <EditText android:id="@+id/cstor_confirm_password"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:password="True"
+                android:singleLine="True"/>
+
+    </LinearLayout>
+</ScrollView>
diff --git a/res/layout/cstor_unlock_dialog_view.xml b/res/layout/cstor_unlock_dialog_view.xml
new file mode 100644
index 0000000..66a2175
--- /dev/null
+++ b/res/layout/cstor_unlock_dialog_view.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:orientation="vertical"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:padding="15dip">
+
+        <TextView android:id="@+id/cstor_error"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:textColor="@color/red"
+                android:textStyle="bold" />
+
+        <EditText android:id="@+id/cstor_password"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:password="True"
+                android:singleLine="True"/>
+
+    </LinearLayout>
+</ScrollView>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a170c92..193388c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -16,5 +16,6 @@
 
 <resources>
     <color name="black">#000</color>
+    <color name="red">#F00</color>
 </resources>
          
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fb806c9..07863b5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1944,11 +1944,13 @@
     <string name="cstor_access_title">Use secure credentials</string>
     <!-- Summary of preference to enable/dislable access to credential storage -->
     <string name="cstor_access_summary">Allow applications to access secure certificates and other credentials</string>
+    <!-- Title of dialog to enable/dislable access to credential storage -->
+    <string name="cstor_access_dialog_title">Enter password</string>
 
     <!-- Title of preference to set storage password -->
-    <string name="cstor_set_passwd_title">Set storage password</string>
+    <string name="cstor_set_passwd_title">Set password</string>
     <!-- Summary of preference to set storage password -->
-    <string name="cstor_set_passwd_summary">Set or change the secure credential storage password</string>
+    <string name="cstor_set_passwd_summary">Set or change the credential storage password</string>
     <!-- Title of dialog to set storage password -->
     <string name="cstor_set_passwd_dialog_title">Set password</string>
 
@@ -1956,7 +1958,16 @@
     <string name="cstor_reset_title">Clear storage</string>
     <!-- Summary of preference to reset storage -->
     <string name="cstor_reset_summary">Clear credential storage of all contents and reset its password</string>
-    <string name="cstor_reset_hint">Are you sure you want to delete all certificates and other stored credentials and reset the password?</string>
+    <string name="cstor_reset_hint">Are you sure you want to delete all credentials and reset the credential storage password?</string>
+
+    <!-- Title of dialog to name a credential -->
+    <string name="cstor_name_credential_dialog_title">Name the certificate</string>
+    <!-- Description for the credential name input box -->
+    <string name="cstor_credential_name">Certificate name:</string>
+    <!-- Title of the credential info -->
+    <string name="cstor_credential_info">Certificate details:</string>
+    <string name="cstor_name_credential_hint">The name can contain only letters and numbers.</string>
+
 
     <!-- Description for the old-password input box -->
     <string name="cstor_old_password">Current password:</string>
@@ -1965,9 +1976,21 @@
     <!-- Description for the confirm-new-password input box -->
     <string name="cstor_confirm_password">Confirm new password:</string>
     <!-- Description when user set up the storage for the very first time -->
-    <string name="cstor_first_time_hint">You must set a password for credential storage before you can store secure certificates and other credentials in it.</string>
-    <string name="cstor_password_error">Passwords do not match.</string>
-    <string name="cstor_password_empty_error">Please fill up all the fields.</string>
+    <string name="cstor_first_time_hint">You must set a password for the credential storage.</string>
+    <string name="cstor_password_error">Please enter the correct password.</string>
+    <string name="cstor_password_error_reset_warning">Please enter the correct password. You have one more try to enter the correct password before the credential storage is erased.</string>
+    <string name="cstor_password_error_reset_warning_plural">Please enter the correct password. You have %d more tries to enter the correct password before the credential storage is erased.</string>
+    <string name="cstor_passwords_error">Passwords do not match.</string>
+    <string name="cstor_passwords_empty_error">You must enter and confirm a password.</string>
+    <string name="cstor_password_empty_error">Please enter the password.</string>
+    <string name="cstor_password_verification_error">Please enter the password again. The password must have at least 8 characters and must not contain spaces.</string>
+    <string name="cstor_name_empty_error">Please enter a name.</string>
+    <string name="cstor_name_char_error">Please enter a name that contains only letters and numbers.</string>
+
+    <!-- toast message -->
+    <string name="cstor_is_enabled">Credential storage is enabled.</string>
+    <!-- toast message -->
+    <string name="cstor_is_added">%s is added.</string>
 
     <!-- Sound settings screen, setting check box label -->
     <string name="emergency_tone_title">Emergency tone</string>
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.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 @@
         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 @@
     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 @@
         if (getIntent().getBooleanExtra("SHOW_USE_LOCATION", false) && !doneUseLocation) {
             showUseLocationDialog(true);
         }
+
+        mCstorHelper.handleCstorIntents(getIntent());
     }
 
     private PreferenceScreen createPreferenceHierarchy() {
@@ -165,7 +194,7 @@
         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 @@
             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 @@
         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 @@
                 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 @@
             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 @@
                 };
         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 @@
     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() {