merge in mnc-release history after reset to mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 588e403..4035af7b 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -67,6 +67,7 @@
 cts_support_packages := \
     CtsAccelerationTestStubs \
     CtsAppTestStubs \
+    CtsCertInstallerApp \
     CtsDeviceAdmin \
     CtsDeviceOpenGl \
     CtsDeviceOwnerApp \
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index b6a7b71..7f43962 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -36,6 +36,8 @@
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 
+LOCAL_AAPT_FLAGS += --version-name "5.0_r1.91 $(BUILD_NUMBER)"
+
 LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index a99408f..4ce9ecd 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -17,8 +17,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
-      android:versionCode="5"
-      android:versionName="5.0_r1.91">
+      android:versionCode="5">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index dc2502c..05c5e77 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -96,6 +96,7 @@
         xml.startTag(null, VERIFIER_INFO_TAG);
         xml.attribute(null, "version-name", Version.getVersionName(mContext));
         xml.attribute(null, "version-code", Integer.toString(Version.getVersionCode(mContext)));
+        xml.attribute(null, "build", Version.getBuildNumber(mContext));
         xml.endTag(null, VERIFIER_INFO_TAG);
 
         xml.startTag(null, DEVICE_INFO_TAG);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/Version.java b/apps/CtsVerifier/src/com/android/cts/verifier/Version.java
index e7b6121..dfe9508 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/Version.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/Version.java
@@ -24,13 +24,21 @@
 class Version {
 
     static String getVersionName(Context context) {
-        return getPackageInfo(context).versionName;
+        return getVersionNameStrings(context)[0];
     }
 
     static int getVersionCode(Context context) {
         return getPackageInfo(context).versionCode;
     }
 
+    static String getBuildNumber(Context context) {
+        return getVersionNameStrings(context)[1];
+    }
+
+    static private String[] getVersionNameStrings(Context context) {
+        return getPackageInfo(context).versionName.split(" ");
+    }
+
     static PackageInfo getPackageInfo(Context context) {
         try {
             PackageManager packageManager = context.getPackageManager();
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index ae4a850..f7af31c 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -39,8 +39,9 @@
         mDevice = getDevice();
     }
 
-    // Collection of all userspace tags
+    // Collection of all userspace tags, and 'sched'
     private static final List<String> sRequiredCategoriesList = Arrays.asList(
+            "sched",
             "gfx",
             "input",
             "view",
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/Android.mk b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
new file mode 100644
index 0000000..22a78e2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsCertInstallerApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CertInstaller/AndroidManifest.xml
new file mode 100644
index 0000000..c50e5fd
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CertInstaller/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.certinstaller">
+
+    <uses-sdk android:minSdkVersion="22"/>
+
+    <application>
+        <activity android:name="CertInstallerActivity">
+            <intent-filter>
+                <action android:name="com.android.cts.certinstaller.install_cert" />
+                <action android:name="com.android.cts.certinstaller.remove_cert" />
+                <action android:name="com.android.cts.certinstaller.verify_cert" />
+                <action android:name="com.android.cts.certinstaller.install_keypair" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/CertInstallerActivity.java b/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/CertInstallerActivity.java
new file mode 100644
index 0000000..b14822b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/CertInstallerActivity.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2015 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.cts.certinstaller;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Base64;
+import android.util.Base64InputStream;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.util.List;
+
+/**
+ * Delegated certificate installer app that responds to specific intents and executes various DPM
+ * certificate manipulation APIs. The following APIs are exercised:
+ * {@link DevicePolicyManager#installCaCert},
+ * {@link DevicePolicyManager#uninstallCaCert},
+ * {@link DevicePolicyManager#hasCaCertInstalled},
+ * {@link DevicePolicyManager#getInstalledCaCerts},
+ * {@link DevicePolicyManager#installKeyPair}.
+ */
+public class CertInstallerActivity extends Activity {
+
+    private static final String TAG = "DelegatedCertInstaller";
+    // exercises {@link DevicePolicyManager#installCaCert} and
+    // {@link DevicePolicyManager#hasCaCertInstalled},
+    private static final String ACTION_INSTALL_CERT = "com.android.cts.certinstaller.install_cert";
+    // exercises {@link DevicePolicyManager#uninstallCaCert} and
+    // {@link DevicePolicyManager#hasCaCertInstalled},
+    private static final String ACTION_REMOVE_CERT = "com.android.cts.certinstaller.remove_cert";
+    // exercises {@link DevicePolicyManager#getInstalledCaCerts},
+    private static final String ACTION_VERIFY_CERT = "com.android.cts.certinstaller.verify_cert";
+    // exercises {@link DevicePolicyManager#installKeyPair},
+    private static final String ACTION_INSTALL_KEYPAIR =
+            "com.android.cts.certinstaller.install_keypair";
+
+    private static final String ACTION_CERT_OPERATION_DONE = "com.android.cts.certinstaller.done";
+
+    private static final String EXTRA_CERT_DATA = "extra_cert_data";
+    private static final String EXTRA_KEY_DATA = "extra_key_data";
+    private static final String EXTRA_KEY_ALIAS = "extra_key_alias";
+    private static final String EXTRA_RESULT_VALUE = "extra_result_value";
+    private static final String EXTRA_RESULT_EXCEPTION = "extra_result_exception";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+        if (intent == null) {
+            finish();
+            return;
+        }
+
+        String action = intent.getAction();
+        DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+
+        byte[] certBuffer;
+
+        if (ACTION_INSTALL_CERT.equals(action)) {
+            try {
+                certBuffer = intent.getByteArrayExtra(EXTRA_CERT_DATA);
+                // Verify cert is not currently installed.
+                if (dpm.hasCaCertInstalled(null, certBuffer)) {
+                    throw new RuntimeException("Cert already on device?");
+                }
+                if (!dpm.installCaCert(null, certBuffer)) {
+                    throw new RuntimeException("installCaCert returned false.");
+                }
+                if (!dpm.hasCaCertInstalled(null, certBuffer)) {
+                    throw new RuntimeException("Cannot find cert after installation.");
+                }
+                sendResult(true, null);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception raised duing ACTION_INSTALL_CERT", e);
+                sendResult(false, e);
+            }
+        } else if (ACTION_REMOVE_CERT.equals(action)) {
+            try {
+                certBuffer = intent.getByteArrayExtra(EXTRA_CERT_DATA);
+                if (!dpm.hasCaCertInstalled(null, certBuffer)) {
+                    throw new RuntimeException("Trying to uninstall a non-existent cert.");
+                }
+                dpm.uninstallCaCert(null, certBuffer);
+                sendResult(!dpm.hasCaCertInstalled(null, certBuffer), null);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception raised duing ACTION_REMOVE_CERT", e);
+                sendResult(false, e);
+            }
+        } else if (ACTION_VERIFY_CERT.equals(action)) {
+            try {
+                certBuffer = intent.getByteArrayExtra(EXTRA_CERT_DATA);
+                sendResult(containsCertificate(dpm.getInstalledCaCerts(null), certBuffer), null);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception raised duing ACTION_VERIFY_CERT", e);
+                sendResult(false, e);
+            }
+        } else if (ACTION_INSTALL_KEYPAIR.equals(action)) {
+            String alias = intent.getStringExtra(EXTRA_KEY_ALIAS);
+            String key = intent.getStringExtra(EXTRA_KEY_DATA);
+            String cert = intent.getStringExtra(EXTRA_CERT_DATA);
+            try {
+                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(
+                        Base64.decode(key, Base64.DEFAULT));
+                KeyFactory kf = KeyFactory.getInstance("RSA");
+                PrivateKey privatekey = kf.generatePrivate(keySpec);
+
+                Certificate certificate = CertificateFactory.getInstance("X.509")
+                        .generateCertificate(
+                                new Base64InputStream(new ByteArrayInputStream(cert.getBytes()),
+                                        Base64.DEFAULT));
+                // Unfortunately there is no programmatically way to check if the given private key
+                // is indeed in the key store as a unprivileged app. So we just rely on
+                // installKeyPair() returning true as the success criteria of this test. Separate
+                // CTS keychain tests will make sure the API's behaviour is correct.
+                // Note: installKeyPair() will silently return false if there is no lockscreen
+                // password, however the test setup should have set one already.
+                sendResult(dpm.installKeyPair(null, privatekey, certificate,  alias), null);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception raised duing ACTION_INSTALL_KEYPAIR", e);
+                sendResult(false, e);
+            }
+        }
+        finish();
+    }
+
+    private void sendResult(boolean succeed, Exception e) {
+        Intent intent = new Intent();
+        intent.setAction(ACTION_CERT_OPERATION_DONE);
+        intent.putExtra(EXTRA_RESULT_VALUE, succeed);
+        if (e != null) {
+            intent.putExtra(EXTRA_RESULT_EXCEPTION, e);
+        }
+        sendBroadcast(intent);
+    }
+
+    private boolean containsCertificate(List<byte[]> certificates, byte[] toMatch)
+            throws CertificateException {
+        Certificate certificateToMatch = readCertificate(toMatch);
+        for (byte[] certBuffer : certificates) {
+            Certificate cert = readCertificate(certBuffer);
+            if (certificateToMatch.equals(cert)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private Certificate readCertificate(byte[] certBuffer) throws CertificateException {
+        final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+        return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index aeb6a45..82f6d6d 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -34,6 +34,15 @@
                 <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
             </intent-filter>
         </receiver>
+        <receiver
+            android:name="com.android.cts.managedprofile.PrimaryUserDeviceAdmin"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                       android:resource="@xml/primary_device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
         <activity android:name=".PrimaryUserFilterSetterActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/primary_device_admin.xml b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/primary_device_admin.xml
new file mode 100644
index 0000000..a6aff49
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/primary_device_admin.xml
@@ -0,0 +1,20 @@
+<!-- Copyright (C) 2015 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.
+-->
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+    <uses-policies>
+         <reset-password />
+         <limit-password />
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DelegatedCertInstallerTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DelegatedCertInstallerTest.java
new file mode 100644
index 0000000..de859b4
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DelegatedCertInstallerTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2015 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.cts.managedprofile;
+
+import android.app.KeyguardManager;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.security.KeyChain;
+import android.security.KeyChainException;
+import android.test.AndroidTestCase;
+import android.util.Base64;
+import android.util.Base64InputStream;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
+
+/**
+ * Exercise delegated cert installer APIs in {@link DevicePolicyManager} by setting the test app
+ * (CtsCertInstallerApp) as a delegated cert installer and then asking it to invoke various
+ * cert-related APIs. The expected certificate changes are validated both remotely and locally.
+ */
+public class DelegatedCertInstallerTest extends AndroidTestCase {
+
+    private static final String CERT_INSTALLER_PACKAGE = "com.android.cts.certinstaller";
+
+    private static final String ACTION_INSTALL_CERT = "com.android.cts.certinstaller.install_cert";
+    private static final String ACTION_REMOVE_CERT = "com.android.cts.certinstaller.remove_cert";
+    private static final String ACTION_VERIFY_CERT = "com.android.cts.certinstaller.verify_cert";
+    private static final String ACTION_INSTALL_KEYPAIR =
+            "com.android.cts.certinstaller.install_keypair";
+    private static final String ACTION_CERT_OPERATION_DONE = "com.android.cts.certinstaller.done";
+
+    private static final String EXTRA_CERT_DATA = "extra_cert_data";
+    private static final String EXTRA_KEY_DATA = "extra_key_data";
+    private static final String EXTRA_KEY_ALIAS = "extra_key_alias";
+    private static final String EXTRA_RESULT_VALUE = "extra_result_value";
+    private static final String EXTRA_RESULT_EXCEPTION = "extra_result_exception";
+
+    /*
+     * The CA and keypair below are generated with:
+     *
+     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
+     * openssl req -newkey rsa:1024 -keyout userkey.pem -nodes -days 3650 -out userkey.req
+     * mkdir -p demoCA/newcerts
+     * touch demoCA/index.txt
+     * echo "01" > demoCA/serial
+     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
+     */
+
+     // Content from cacert.pem
+    private static final String TEST_CA =
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDXTCCAkWgAwIBAgIJAK9Tl/F9V8kSMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n" +
+            "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n" +
+            "aWRnaXRzIFB0eSBMdGQwHhcNMTUwMzA2MTczMjExWhcNMjUwMzAzMTczMjExWjBF\n" +
+            "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n" +
+            "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +
+            "CgKCAQEAvItOutsE75WBTgTyNAHt4JXQ3JoseaGqcC3WQij6vhrleWi5KJ0jh1/M\n" +
+            "Rpry7Fajtwwb4t8VZa0NuM2h2YALv52w1xivql88zce/HU1y7XzbXhxis9o6SCI+\n" +
+            "oVQSbPeXRgBPppFzBEh3ZqYTVhAqw451XhwdA4Aqs3wts7ddjwlUzyMdU44osCUg\n" +
+            "kVg7lfPf9sTm5IoHVcfLSCWH5n6Nr9sH3o2ksyTwxuOAvsN11F/a0mmUoPciYPp+\n" +
+            "q7DzQzdi7akRG601DZ4YVOwo6UITGvDyuAAdxl5isovUXqe6Jmz2/myTSpAKxGFs\n" +
+            "jk9oRoG6WXWB1kni490GIPjJ1OceyQIDAQABo1AwTjAdBgNVHQ4EFgQUH1QIlPKL\n" +
+            "p2OQ/AoLOjKvBW4zK3AwHwYDVR0jBBgwFoAUH1QIlPKLp2OQ/AoLOjKvBW4zK3Aw\n" +
+            "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcMi4voMMJHeQLjtq8Oky\n" +
+            "Azpyk8moDwgCd4llcGj7izOkIIFqq/lyqKdtykVKUWz2bSHO5cLrtaOCiBWVlaCV\n" +
+            "DYAnnVLM8aqaA6hJDIfaGs4zmwz0dY8hVMFCuCBiLWuPfiYtbEmjHGSmpQTG6Qxn\n" +
+            "ZJlaK5CZyt5pgh5EdNdvQmDEbKGmu0wpCq9qjZImwdyAul1t/B0DrsWApZMgZpeI\n" +
+            "d2od0VBrCICB1K4p+C51D93xyQiva7xQcCne+TAnGNy9+gjQ/MyR8MRpwRLv5ikD\n" +
+            "u0anJCN8pXo6IMglfMAsoton1J6o5/ae5uhC6caQU8bNUsCK570gpNfjkzo6rbP0\n" +
+            "wQ==\n" +
+            "-----END CERTIFICATE-----";
+    // Content from userkey.pem without the private key header and footer.
+    private static final String TEST_KEY =
+            "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALCYprGsTU+5L3KM\n" +
+            "fhkm0gXM2xjGUH+543YLiMPGVr3eVS7biue1/tQlL+fJsw3rqsPKJe71RbVWlpqU\n" +
+            "mhegxG4s3IvGYVB0KZoRIjDKmnnvlx6nngL2ZJ8O27U42pHsw4z4MKlcQlWkjL3T\n" +
+            "9sV6zW2Wzri+f5mvzKjhnArbLktHAgMBAAECgYBlfVVPhtZnmuXJzzQpAEZzTugb\n" +
+            "tN1OimZO0RIocTQoqj4KT+HkiJOLGFQPwbtFpMre+q4SRqNpM/oZnI1yRtKcCmIc\n" +
+            "mZgkwJ2k6pdSxqO0ofxFFTdT9czJ3rCnqBHy1g6BqUQFXT4olcygkxUpKYUwzlz1\n" +
+            "oAl487CoPxyr4sVEAQJBANwiUOHcdGd2RoRILDzw5WOXWBoWPOKzX/K9wt0yL+mO\n" +
+            "wlFNFSymqo9eLheHcEq/VD9qK9rT700dCewJfWj6+bECQQDNXmWNYIxGii5NJilT\n" +
+            "OBOHiMD/F0NE178j+/kmacbhDJwpkbLYXaP8rW4+Iswrm4ORJ59lvjNuXaZ28+sx\n" +
+            "fFp3AkA6Z7Bl/IO135+eATgbgx6ZadIqObQ1wbm3Qbmtzl7/7KyJvZXcnuup1icM\n" +
+            "fxa//jtwB89S4+Ad6ZJ0WaA4dj5BAkEAuG7V9KmIULE388EZy8rIfyepa22Q0/qN\n" +
+            "hdt8XasRGHsio5Jdc0JlSz7ViqflhCQde/aBh/XQaoVgQeO8jKyI8QJBAJHekZDj\n" +
+            "WA0w1RsBVVReN1dVXgjm1CykeAT8Qx8TUmBUfiDX6w6+eGQjKtS7f4KC2IdRTV6+\n" +
+            "bDzDoHBChHNC9ms=\n";
+
+    // Content from usercert.pem without the header and footer.
+    private static final String TEST_CERT =
+            "MIIDEjCCAfqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJBVTET\n" +
+            "MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ\n" +
+            "dHkgTHRkMB4XDTE1MDUwMTE2NTQwNVoXDTI1MDQyODE2NTQwNVowWzELMAkGA1UE\n" +
+            "BhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp\n" +
+            "ZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLY2xpZW50IGNlcnQwgZ8wDQYJKoZIhvcN\n" +
+            "AQEBBQADgY0AMIGJAoGBALCYprGsTU+5L3KMfhkm0gXM2xjGUH+543YLiMPGVr3e\n" +
+            "VS7biue1/tQlL+fJsw3rqsPKJe71RbVWlpqUmhegxG4s3IvGYVB0KZoRIjDKmnnv\n" +
+            "lx6nngL2ZJ8O27U42pHsw4z4MKlcQlWkjL3T9sV6zW2Wzri+f5mvzKjhnArbLktH\n" +
+            "AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2Vu\n" +
+            "ZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ8GL+jKSarvTn9fVNA2AzjY7qq\n" +
+            "gjAfBgNVHSMEGDAWgBRzBBA5sNWyT/fK8GrhN3tOqO5tgjANBgkqhkiG9w0BAQsF\n" +
+            "AAOCAQEAgwQEd2bktIDZZi/UOwU1jJUgGq7NiuBDPHcqgzjxhGFLQ8SQAAP3v3PR\n" +
+            "mLzcfxsxnzGynqN5iHQT4rYXxxaqrp1iIdj9xl9Wl5FxjZgXITxhlRscOd/UOBvG\n" +
+            "oMrazVczjjdoRIFFnjtU3Jf0Mich68HD1Z0S3o7X6sDYh6FTVR5KbLcxbk6RcoG4\n" +
+            "VCI5boR5LUXgb5Ed5UxczxvN12S71fyxHYVpuuI0z0HTIbAxKeRw43I6HWOmR1/0\n" +
+            "G6byGCNL/1Fz7Y+264fGqABSNTKdZwIU2K4ANEH7F+9scnhoO6OBp+gjBe5O+7jb\n" +
+            "wZmUCAoTka4hmoaOCj7cqt/IkmxozQ==\n";
+
+    private DevicePolicyManager mDpm;
+    private volatile boolean mReceivedResult;
+    private volatile Exception mReceivedException;
+    private Semaphore mAvailableResultSemaphore;
+
+    private final BroadcastReceiver receiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_CERT_OPERATION_DONE.equals(intent.getAction())) {
+                synchronized (DelegatedCertInstallerTest.this) {
+                    mReceivedResult = intent.getBooleanExtra(EXTRA_RESULT_VALUE, false);
+                    mReceivedException =
+                            (Exception) intent.getSerializableExtra(EXTRA_RESULT_EXCEPTION);
+                    mAvailableResultSemaphore.release();
+                }
+            }
+        }
+    };
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        mAvailableResultSemaphore = new Semaphore(0);
+        mReceivedResult = false;
+        mReceivedException = null;
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_CERT_OPERATION_DONE);
+        getContext().registerReceiver(receiver, filter);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        getContext().unregisterReceiver(receiver);
+        mDpm.uninstallCaCert(ADMIN_RECEIVER_COMPONENT, TEST_CA.getBytes());
+        // Installed private key pair will be removed once the lockscreen password is cleared,
+        // which is done in the hostside test.
+        mDpm.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, null);
+        super.tearDown();
+    }
+
+    public void testCaCertsOperations() throws InterruptedException {
+        byte[] cert = TEST_CA.getBytes();
+
+        mDpm.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, CERT_INSTALLER_PACKAGE);
+        assertEquals(CERT_INSTALLER_PACKAGE,
+                mDpm.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT));
+
+        // Exercise installCaCert()
+        installCaCert(cert);
+        assertResult("installCaCert", true);
+        assertTrue("Certificate is not installed properly", mDpm.hasCaCertInstalled(
+                ADMIN_RECEIVER_COMPONENT, cert));
+
+        // Exercise getInstalledCaCerts()
+        verifyCaCert(cert);
+        assertResult("getInstalledCaCerts()", true);
+
+        // Exercise uninstallCaCert()
+        removeCaCert(cert);
+        assertResult("uninstallCaCert()", true);
+        assertFalse("Certificate is not removed properly", mDpm.hasCaCertInstalled(
+                ADMIN_RECEIVER_COMPONENT, cert));
+
+        // Clear delegated cert installer.
+        // Tests after this are expected to fail.
+        mDpm.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, null);
+
+        installCaCert(cert);
+        assertResult("installCaCert", false);
+    }
+
+    public void testInstallKeyPair() throws InterruptedException, KeyChainException {
+        final String alias = "delegated-cert-installer-test-key";
+
+        // Clear delegated cert installer.
+        mDpm.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, null);
+        // The app is not the cert installer , it shouldn't have have privilege to call
+        // installKeyPair().
+        installKeyPair(TEST_KEY, TEST_CERT, alias);
+        assertResult("installKeyPair", false);
+
+        // Set the app to be cert installer.
+        mDpm.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, CERT_INSTALLER_PACKAGE);
+        assertEquals(CERT_INSTALLER_PACKAGE,
+                mDpm.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT));
+
+        // Exercise installKeyPair()
+        checkKeyguardPrecondition();
+        installKeyPair(TEST_KEY, TEST_CERT, alias);
+        assertResult("installKeyPair", true);
+    }
+
+    /**
+     * installKeyPair() requires the system to have a lockscreen password, which should have been
+     * set by the host side test.
+     */
+    private void checkKeyguardPrecondition() throws InterruptedException {
+        KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        if (!km.isKeyguardSecure()) {
+            Thread.sleep(5000);
+          }
+          assertTrue("A lockscreen password is required before keypair can be installed",
+                          km.isKeyguardSecure());
+    }
+
+    private void installCaCert(byte[] cert) {
+        Intent intent = new Intent();
+        intent.setAction(ACTION_INSTALL_CERT);
+        intent.putExtra(EXTRA_CERT_DATA, cert);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getContext().startActivity(intent);
+    }
+
+    private void removeCaCert(byte[] cert) {
+        Intent intent = new Intent();
+        intent.setAction(ACTION_REMOVE_CERT);
+        intent.putExtra(EXTRA_CERT_DATA, cert);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getContext().startActivity(intent);
+    }
+
+    private void verifyCaCert(byte[] cert) {
+        Intent intent = new Intent();
+        intent.setAction(ACTION_VERIFY_CERT);
+        intent.putExtra(EXTRA_CERT_DATA, cert);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getContext().startActivity(intent);
+    }
+
+    private void assertResult(String testName, Boolean expectSuccess) throws InterruptedException {
+        assertTrue("Cert installer did not respond in time.",
+                mAvailableResultSemaphore.tryAcquire(5, TimeUnit.SECONDS));
+        synchronized (this) {
+            if (expectSuccess) {
+                assertTrue(testName + " failed unexpectedly.", mReceivedResult);
+                assertNull(testName + " raised exception", mReceivedException);
+            } else {
+                assertFalse(testName + " succeeded unexpectedly.", mReceivedResult);
+                assertTrue(testName + " did not raise SecurityException",
+                        mReceivedException != null &&
+                        mReceivedException instanceof SecurityException);
+            }
+        }
+    }
+
+    private void installKeyPair(String key, String cert, String alias) {
+        Intent intent = new Intent();
+        intent.setAction(ACTION_INSTALL_KEYPAIR);
+        intent.putExtra(EXTRA_CERT_DATA, cert);
+        intent.putExtra(EXTRA_KEY_DATA, key);
+        intent.putExtra(EXTRA_KEY_ALIAS, alias);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getContext().startActivity(intent);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
new file mode 100644
index 0000000..5b8af1f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 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.cts.managedprofile;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+/**
+ * This test executes helper tasks as active device admin in the primary user. Current tasks are
+ * setting and clearing lockscreen password used by the host side delegated cert installer test.
+ */
+public class PrimaryUserAdminHelper extends AndroidTestCase {
+
+    private DevicePolicyManager mDpm;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+    }
+
+    /**
+     * Device admin can only be deactivated by itself and this test should be executed before the
+     * device admin package can be uninstalled.
+     */
+    public void testClearDeviceAdmin() {
+        try {
+            removeActiveAdmin(mDpm, PrimaryUserDeviceAdmin.ADMIN_RECEIVER_COMPONENT);
+        } catch (InterruptedException e) {
+            fail("Removal of device admin interrupted.");
+        }
+        assertFalse(mDpm.isAdminActive(PrimaryUserDeviceAdmin.ADMIN_RECEIVER_COMPONENT));
+    }
+
+    /**
+     * Set lockscreen password.
+     */
+    public void testSetPassword() {
+        // Enable credential storage by setting a nonempty password.
+        assertTrue(mDpm.resetPassword("test", 0));
+    }
+
+    /**
+     * Clear lockscreen password.
+     */
+    public void testClearPassword() {
+        mDpm.setPasswordQuality(PrimaryUserDeviceAdmin.ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+        mDpm.setPasswordMinimumLength(
+                PrimaryUserDeviceAdmin.ADMIN_RECEIVER_COMPONENT, 0);
+        assertTrue(mDpm.resetPassword("", 0));
+    }
+
+    private void removeActiveAdmin(DevicePolicyManager dpm, ComponentName cn)
+            throws InterruptedException {
+        if (mDpm.isAdminActive(cn)) {
+            mDpm.removeActiveAdmin(cn);
+            // Wait until device admin is not active.
+            for (int i = 0; i < 1000 && dpm.isAdminActive(cn); i++) {
+                Thread.sleep(100);
+            }
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserDeviceAdmin.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserDeviceAdmin.java
new file mode 100644
index 0000000..8662daf
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserDeviceAdmin.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 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.cts.managedprofile;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+
+/**
+ * A device admin class running in the primary user. Currently used by delegated cert installer
+ * test to set a lockscreen password which is prerequisite of installKeyPair().
+ */
+public class PrimaryUserDeviceAdmin extends DeviceAdminReceiver {
+    public static final ComponentName ADMIN_RECEIVER_COMPONENT = new ComponentName(
+            PrimaryUserDeviceAdmin.class.getPackage().getName(),
+            PrimaryUserDeviceAdmin.class.getName());
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 7e0d9595..5904a6f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -335,4 +335,12 @@
         assertTrue(commandOutput + " expected to start with \"Success:\"",
                 commandOutput.startsWith("Success:"));
     }
+
+    protected void setDeviceAdmin(String componentName) throws DeviceNotAvailableException {
+        String command = "dpm set-active-admin '" + componentName + "'";
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+        assertTrue(commandOutput + " expected to start with \"Success:\"",
+                commandOutput.startsWith("Success:"));
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 3954bda..5c2048e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -36,6 +36,9 @@
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
     private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
+    private static final String CERT_INSTALLER_PKG = "com.android.cts.certinstaller";
+    private static final String CERT_INSTALLER_APK = "CtsCertInstallerApp.apk";
+
     private static final String ADMIN_RECEIVER_TEST_CLASS =
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
 
@@ -66,6 +69,7 @@
             getDevice().uninstallPackage(MANAGED_PROFILE_PKG);
             getDevice().uninstallPackage(INTENT_SENDER_PKG);
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
+            getDevice().uninstallPackage(CERT_INSTALLER_PKG);
         }
         super.tearDown();
     }
@@ -380,6 +384,28 @@
                 "testSetBluetoothContactSharingDisabled_setterAndGetter", mUserId));
     }
 
+    public void testDelegatedCertInstaller() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installApp(CERT_INSTALLER_APK);
+        setDeviceAdmin(MANAGED_PROFILE_PKG + "/.PrimaryUserDeviceAdmin");
+
+        final String adminHelperClass = ".PrimaryUserAdminHelper";
+        try {
+            assertTrue("Set lockscreen password failed", runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    adminHelperClass, "testSetPassword", 0 /* user 0 */));
+            assertTrue("DelegatedCertInstaller failed", runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    ".DelegatedCertInstallerTest", mUserId));
+        } finally {
+            // Reset lockscreen password and remove device admin.
+            assertTrue("Clear lockscreen password failed", runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    adminHelperClass, "testClearPassword", 0 /* user 0 */));
+            assertTrue("Clear device admin failed", runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    adminHelperClass, "testClearDeviceAdmin", 0 /* user 0 */));
+        }
+    }
+
     private void disableActivityForUser(String activityName, int userId)
             throws DeviceNotAvailableException {
         String command = "am start -W --user " + userId
diff --git a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 08a905b..41332c7 100644
--- a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -679,6 +679,19 @@
         }
     }
 
+    public void testInstallCaCert_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testInstallCaCert_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.installCaCert(null, TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
     public void testUninstallCaCert_failIfNotProfileOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testUninstallCaCert_failIfNotProfileOwner");
@@ -693,6 +706,19 @@
         }
     }
 
+    public void testUninstallCaCert_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testUninstallCaCert_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.uninstallCaCert(null, TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
     public void testGetInstalledCaCerts_failIfNotProfileOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testGetInstalledCaCerts_failIfNotProfileOwner");
@@ -706,6 +732,19 @@
         }
     }
 
+    public void testGetInstalledCaCerts_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testGetInstalledCaCerts_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.getInstalledCaCerts(null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
     public void testHasCaCertInstalled_failIfNotProfileOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testHasCaCertInstalled_failIfNotProfileOwner");
@@ -720,6 +759,19 @@
         }
     }
 
+    public void testHasCaCertInstalled_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testHasCaCertInstalled_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.hasCaCertInstalled(null, TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
     public void testUninstallAllUserCaCerts_failIfNotProfileOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testUninstallAllUserCaCerts_failIfNotProfileOwner");
@@ -733,6 +785,19 @@
         }
     }
 
+    public void testUninstallAllUserCaCerts_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testUninstallAllUserCaCerts_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.uninstallAllUserCaCerts(null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
     public void testSetScreenCaptureDisabled_failIfNotProfileOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testSetScreenCaptureDisabled_failIfNotProfileOwner");
@@ -961,4 +1026,30 @@
         assertTrue("Password '" + password + "' failed on " + restriction, passwordResetResult);
         assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
     }
+
+    public void testSetDelegatedCertInstaller_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetDelegatedCertInstaller_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setCertInstallerPackage(mComponent, "com.test.package");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testGetDelegatedCertInstaller_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testGetDelegatedCertInstaller_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.getCertInstallerPackage(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index d76152f..4450339 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -390,7 +390,7 @@
 
     // TODO: after L release move to SensorBatchingTests and run in all sensors with default
     //       verifications enabled
-    public void testBatchAndFlushWithMutipleSensors() throws Exception {
+    public void testBatchAndFlushWithMultipleSensors() throws Exception {
         final int maxSensors = 3;
         final int maxReportLatencyUs = (int) TimeUnit.SECONDS.toMicros(10);
         List<Sensor> sensorsToTest = new ArrayList<Sensor>();
diff --git a/tests/tests/location/src/android/location/cts/LocationTest.java b/tests/tests/location/src/android/location/cts/LocationTest.java
index f037109..b60b8b1 100644
--- a/tests/tests/location/src/android/location/cts/LocationTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationTest.java
@@ -16,8 +16,15 @@
 
 package android.location.cts;
 
-
+import android.content.Context;
+import android.content.Intent;
 import android.location.Location;
+import android.location.SettingInjectorService;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
@@ -41,6 +48,9 @@
     private final boolean TEST_KEY1VALUE = false;
     private final byte TEST_KEY2VALUE = 10;
 
+    private static final String ENABLED_KEY = "enabled";
+    private static final String MESSENGER_KEY = "messenger";
+
     public void testConstructor() {
         new Location("LocationProvider");
 
@@ -407,6 +417,56 @@
         assertTestLocation(newLocation);
     }
 
+    public void testSettingInjectorService() {
+        Context c = getContext();
+        SettingInjectorServiceDerived service = new SettingInjectorServiceDerived();
+
+        assertNotNull(c);
+
+        Intent intent =
+            new Intent(c, android.location.SettingInjectorService.class);
+
+        assertNotNull(c.getMainLooper());
+        SettingInjectorResultHandler resultHandler =
+            new SettingInjectorResultHandler(c.getMainLooper());
+
+        Messenger m = new Messenger(resultHandler);
+        intent.putExtra(MESSENGER_KEY, m);
+
+        int ret;
+        final long timeout = 500;
+
+        // should refuse binding
+        IBinder binder = service.onBind(intent);
+        assertNull("onBind should always fail.", binder);
+
+        // test if result consistent with the truth
+        // enabled == false case
+        service.setEnabled(false);
+        resultHandler.expectEnabled(false);
+        resultHandler.expectMessage(true);
+        ret = service.onStartCommand(intent, SettingInjectorService.START_NOT_STICKY, 0);
+        assertEquals("onStartCommand return value invalid in (enabled == false) case.",
+            ret, SettingInjectorService.START_NOT_STICKY);
+        assertTrue("Message time out in (enabled == false case).",
+            resultHandler.waitForMessage(timeout));
+
+        // enabled == true case
+        service.setEnabled(true);
+        resultHandler.expectEnabled(true);
+        resultHandler.expectMessage(true);
+        ret = service.onStartCommand(intent, SettingInjectorService.START_NOT_STICKY, 0);
+        assertEquals("onStartCommand return value invalid in (enabled == true) case.",
+            ret, SettingInjectorService.START_NOT_STICKY);
+        assertTrue("Message time out in (enabled == true) case.",
+            resultHandler.waitForMessage(timeout));
+
+        // should not respond to the deprecated method
+        resultHandler.expectMessage(false);
+        service.onStart(intent, 0);
+        resultHandler.waitForMessage(timeout);
+    }
+
     private void assertTestLocation(Location l) {
         assertNotNull(l);
         assertEquals(TEST_PROVIDER, l.getProvider());
@@ -441,4 +501,79 @@
         assertFalse(bundle.getBoolean(TEST_KEY1NAME));
         assertEquals(TEST_KEY2VALUE, bundle.getByte(TEST_KEY2NAME));
     }
+
+    private class SettingInjectorResultHandler extends Handler {
+        private boolean mEnabledShouldBe;
+        private boolean mExpectingMessage;
+        private boolean mMessageArrived;
+
+        SettingInjectorResultHandler(Looper l) {
+            super(l);
+        }
+
+        @Override
+        public void handleMessage(Message m) {
+
+            assertTrue("Unexpected message.", mExpectingMessage);
+
+            boolean enabled = m.getData().getBoolean(ENABLED_KEY);
+
+            assertEquals(String.format(
+                    "Message value (%s) inconsistent with service state (%s).",
+                    String.valueOf(enabled), String.valueOf(mEnabledShouldBe) ),
+                    mEnabledShouldBe, enabled);
+
+            synchronized (this) {
+                mMessageArrived = true;
+                notify();
+            }
+        }
+
+        public void expectEnabled(boolean enabled) {
+            mEnabledShouldBe = enabled;
+        }
+
+        public void expectMessage(boolean expecting) {
+            mMessageArrived = false;
+            mExpectingMessage = expecting;
+        }
+
+        public synchronized boolean waitForMessage(long millis) {
+            synchronized (this) {
+                try {
+                    wait(millis);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                return mMessageArrived;
+            }
+        }
+    }
+
+
+    private class SettingInjectorServiceDerived extends SettingInjectorService {
+
+        private boolean mEnabled;
+
+        SettingInjectorServiceDerived() {
+            super("SettingInjectorServiceDerived");
+            setEnabled(false);
+        }
+
+        @Override
+        // Deprecated API
+        protected String onGetSummary() {
+            return "";
+        }
+
+        @Override
+        protected boolean onGetEnabled() {
+            return mEnabled;
+        }
+
+        public void setEnabled(boolean enabled) {
+            mEnabled = enabled;
+        }
+    }
+
 }
diff --git a/tests/tests/media/src/android/media/cts/EnumDevicesTest.java b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
index 73a6314..f513709 100644
--- a/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
+++ b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
@@ -95,6 +95,10 @@
         deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL);
         for (int index = 0; index < deviceList.length; index++) {
             AudioDeviceInfo deviceInfo = deviceList[index];
+
+            // we don't say anything about the returned value.
+            int id = deviceInfo.getId();
+
             // Product Name
             CharSequence productName = deviceInfo.getProductName();
             assertNotNull(productName);
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java
index b96d38c..2473078 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java
@@ -248,12 +248,14 @@
 
         if (null == mCrypto && (mEncryptedVideo || mEncryptedAudio)) {
             try {
-                mCrypto = new MediaCrypto(CLEARKEY_SCHEME_UUID, mSessionId);
+                byte[] initData = new byte[0];
+                mCrypto = new MediaCrypto(CLEARKEY_SCHEME_UUID, initData);
             } catch (MediaCryptoException e) {
                 reset();
                 Log.e(TAG, "Failed to create MediaCrypto instance.");
                 throw e;
             }
+            mCrypto.setMediaDrmSession(mSessionId);
         } else {
             reset();
             mCrypto.release();
diff --git a/tests/tests/media/src/android/media/cts/RoutingTest.java b/tests/tests/media/src/android/media/cts/RoutingTest.java
index d641734..c0e9a3e 100644
--- a/tests/tests/media/src/android/media/cts/RoutingTest.java
+++ b/tests/tests/media/src/android/media/cts/RoutingTest.java
@@ -33,6 +33,8 @@
 
 import android.util.Log;
 
+import java.lang.Runnable;
+
 /**
  * TODO: Insert description here. (generated by pmclean)
  */
@@ -220,4 +222,130 @@
 
         audioRecord.release();
     }
+
+    private class AudioTrackFiller implements Runnable {
+        AudioTrack mAudioTrack;
+        int mBufferSize;
+
+        boolean mPlaying;
+
+        short[] mAudioData;
+
+        public AudioTrackFiller(AudioTrack audioTrack, int bufferSize) {
+            mAudioTrack = audioTrack;
+            mBufferSize = bufferSize;
+            mPlaying = false;
+
+            // setup audio data (silence will suffice)
+            mAudioData = new short[mBufferSize];
+            for (int index = 0; index < mBufferSize; index++) {
+                mAudioData[index] = 0;
+            }
+        }
+
+        public void start() { mPlaying = true; }
+        public void stop() { mPlaying = false; }
+
+        @Override
+        public void run() {
+            while (mAudioTrack != null && mPlaying) {
+                mAudioTrack.write(mAudioData, 0, mBufferSize);
+            }
+        }
+    }
+
+    public void test_audioTrack_getRoutedDevice() {
+        int bufferSize =
+                AudioTrack.getMinBufferSize(
+                    41000,
+                    AudioFormat.CHANNEL_OUT_STEREO,
+                    AudioFormat.ENCODING_PCM_16BIT);
+        AudioTrack audioTrack =
+            new AudioTrack(
+                AudioManager.STREAM_MUSIC,
+                41000,
+                AudioFormat.CHANNEL_OUT_STEREO,
+                AudioFormat.ENCODING_PCM_16BIT,
+                bufferSize,
+                AudioTrack.MODE_STREAM);
+
+        AudioTrackFiller filler = new AudioTrackFiller(audioTrack, bufferSize);
+        filler.start();
+
+        audioTrack.play();
+
+        Thread fillerThread = new Thread(filler);
+        fillerThread.start();
+
+        try { Thread.sleep(1000); } catch (InterruptedException ex) {}
+
+        // No explicit route
+        AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
+        assertNotNull(routedDevice); // we probably can't say anything more than this
+
+        filler.stop();
+        audioTrack.stop();
+        audioTrack.release();
+    }
+
+    private class AudioRecordPuller implements Runnable {
+        AudioRecord mAudioRecord;
+        int mBufferSize;
+
+        boolean mRecording;
+
+        short[] mAudioData;
+
+        public AudioRecordPuller(AudioRecord audioRecord, int bufferSize) {
+            mAudioRecord = audioRecord;
+            mBufferSize = bufferSize;
+            mRecording = false;
+        }
+
+        public void start() { mRecording = true; }
+        public void stop() { mRecording = false; }
+
+        @Override
+        public void run() {
+            while (mAudioRecord != null && mRecording) {
+                mAudioRecord.read(mAudioData, 0, mBufferSize);
+           }
+        }
+    }
+
+    public void test_audioRecord_getRoutedDevice() {
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+            return;
+        }
+
+        int bufferSize =
+                AudioRecord.getMinBufferSize(
+                    41000,
+                    AudioFormat.CHANNEL_OUT_DEFAULT,
+                    AudioFormat.ENCODING_PCM_16BIT);
+        AudioRecord audioRecord =
+            new AudioRecord(
+                MediaRecorder.AudioSource.DEFAULT,
+                41000, AudioFormat.CHANNEL_OUT_DEFAULT,
+                AudioFormat.ENCODING_PCM_16BIT,
+                bufferSize);
+
+        AudioRecordPuller puller = new AudioRecordPuller(audioRecord, bufferSize);
+        puller.start();
+
+        audioRecord.startRecording();
+
+        Thread pullerThread = new Thread(puller);
+        pullerThread.start();
+
+        try { Thread.sleep(1000); } catch (InterruptedException ex) {}
+
+        // No explicit route
+        AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
+        assertNotNull(routedDevice); // we probably can't say anything more than this
+
+        puller.stop();
+        audioRecord.stop();
+        audioRecord.release();
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
index 81a1a4b..4fadafc 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -383,6 +383,34 @@
         assertEquals(1, mAdapterView.getSelectedItemId());
         assertEquals(1, mAdapterView.getSelectedItemPosition());
         assertEquals(FRUIT[1], mAdapterView.getSelectedItem());
+
+        // Ensure getSelectedItemZzz() synchronizes after data set change.
+        ArrayAdapter<String> adapter = new ArrayAdapter<>(
+                getActivity(), android.R.layout.simple_list_item_1);
+        adapter.add(FRUIT[0]);
+        adapter.add(FRUIT[1]);
+
+        ListAdapter previousAdapter = mAdapterView.getAdapter();
+        mAdapterView.setAdapter(adapter);
+        mAdapterView.setSelection(1);
+        assertEquals("Initial getSelectedItemId() is correct",
+                1, mAdapterView.getSelectedItemId());
+        assertEquals("Initial getSelectedItemPosition() is correct",
+                1, mAdapterView.getSelectedItemPosition());
+
+        adapter.remove(FRUIT[0]);
+        assertEquals("Synchronized getSelectedItemId() after data set invalidation",
+                0, mAdapterView.getSelectedItemId());
+        assertEquals("Synchronized getSelectedItemPosition() after data set invalidation",
+                0, mAdapterView.getSelectedItemPosition());
+
+        adapter.clear();
+        assertEquals("Synchronized getSelectedItemId() after data set cleared",
+                AdapterView.INVALID_ROW_ID, mAdapterView.getSelectedItemId());
+        assertEquals("Synchronized getSelectedItemPosition() after data set cleared",
+                AdapterView.INVALID_POSITION, mAdapterView.getSelectedItemPosition());
+
+        mAdapterView.setAdapter(previousAdapter);
     }
 
     /*