Add CredentialInstaller.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0cb88f1..5225b9b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -313,13 +313,20 @@
                 <action android:name="android.settings.SECURITY_SETTINGS" />
                 <action android:name="android.settings.LOCATION_SOURCE_SETTINGS" />
                 <action android:name="android.credentials.UNLOCK" />
-                <action android:name="android.credentials.SYSTEM_INSTALL" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.VOICE_LAUNCH" />
                 <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
         </activity>
 
+        <activity android:name="CredentialInstaller"
+                android:label="@string/credential_installer_activity_title">
+            <intent-filter>
+                <action android:name="android.credentials.SYSTEM_INSTALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="PrivacySettings"
                 android:label="@string/privacy_settings_title"
                 android:configChanges="orientation|keyboardHidden"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2ad8fed..23ac7ba 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1907,6 +1907,9 @@
     <string name="gadget_toggle_wifi">Updating Wi-Fi setting</string>
     <string name="gadget_toggle_bluetooth">Updating Bluetooth setting</string>
 
+    <!-- credential installer title -->
+    <string name="credential_installer_activity_title">Credential installer</string>
+
     <string name="vpn_settings_activity_title">VPN settings</string>
 
     <!-- Title of VPN connect dialog -->
diff --git a/src/com/android/settings/CredentialInstaller.java b/src/com/android/settings/CredentialInstaller.java
new file mode 100644
index 0000000..5a457d7
--- /dev/null
+++ b/src/com/android/settings/CredentialInstaller.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+package com.android.settings;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.util.Log;
+
+/**
+ * Installs credentials to the system keystore. It reacts to the
+ * {@link Credentials#SYSTEM_INSTALL_ACTION} intent. All the key-value pairs in
+ * the intent are installed to the system keystore. For security reason, the
+ * current implementation limits that only com.android.certinstaller can use
+ * this service.
+ */
+public class CredentialInstaller extends Activity {
+    private static final String TAG = "CredentialInstaller";
+
+    private KeyStore mKeyStore = KeyStore.getInstance();
+    private boolean mUnlocking = false;
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        if (!"com.android.certinstaller".equals(getCallingPackage())) finish();
+
+        if (!isKeyStoreLocked()) {
+            install();
+            finish();
+        } else if (!mUnlocking) {
+            mUnlocking = true;
+            Credentials.getInstance().unlock(this);
+        } else {
+            finish();
+        }
+    }
+
+    private void install() {
+        Intent intent = getIntent();
+        Bundle bundle = (intent == null) ? null : intent.getExtras();
+        if (bundle == null) return;
+        for (String key : bundle.keySet()) {
+            byte[] data = bundle.getByteArray(key);
+            if (data == null) continue;
+            boolean success = mKeyStore.put(key.getBytes(), data);
+            Log.v(TAG, "install " + key + ": " + data.length + "  success? " + success);
+            if (!success) return;
+        }
+        setResult(RESULT_OK);
+    }
+
+    private boolean isKeyStoreLocked() {
+        return (mKeyStore.test() != KeyStore.NO_ERROR);
+    }
+}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index cdfd8bd..80300e0 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -380,9 +380,6 @@
                 mExternalIntent = intent;
                 showCstorDialog(mState == KeyStore.UNINITIALIZED
                         ? CSTOR_INIT_DIALOG : CSTOR_UNLOCK_DIALOG);
-            } else if (Credentials.SYSTEM_INSTALL_ACTION.equals(action)) {
-                mExternalIntent = intent;
-                // TODO: unlock and install.
             }
         }
 
@@ -460,12 +457,7 @@
                 removeDialog(mDialogId);
 
                 if (mExternalIntent != null) {
-                    if (Credentials.SYSTEM_INSTALL_ACTION.equals(
-                                    mExternalIntent.getAction())) {
-                        // TODO: install if unlocked.
-                    } else {
-                        finish();
-                    }
+                    finish();
                 }
             }
         }