Merge "Fixed compareBitmaps(Bitmap bmp1, Bitmap bmp2) method." into nyc-dev
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 79e8a36..41f7b48 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -46,7 +46,7 @@
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
 
 LOCAL_DEX_PREOPT := false
 
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index c9ee92a..bae1bfa 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -35,7 +35,6 @@
 import com.android.tradefed.config.Option.Importance;
 import com.android.tradefed.config.OptionClass;
 import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.FileInputStreamSource;
 import com.android.tradefed.result.ILogSaver;
 import com.android.tradefed.result.ILogSaverListener;
 import com.android.tradefed.result.ITestInvocationListener;
@@ -358,12 +357,12 @@
                 }
                 // Save the full results folder.
                 if (zippedResults != null) {
-                    FileInputStreamSource fiss = null;
+                    FileInputStream zipResultStream = null;
                     try {
-                        fiss =  new FileInputStreamSource(zippedResults);
-                        testLog("results", LogDataType.ZIP, fiss);
+                        zipResultStream =  new FileInputStream(zippedResults);
+                        mLogSaver.saveLogData("results", LogDataType.ZIP, zipResultStream);
                     } finally {
-                        StreamUtil.cancel(fiss);
+                        StreamUtil.close(zipResultStream);
                     }
                 }
             }
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index 8e435d8..655add8 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -53,6 +53,7 @@
     private static final String BUILD_PRODUCT = "build_product";
     private static final String BUILD_TAG = "Build";
     private static final String CASE_TAG = "TestCase";
+    private static final String DETAIL_TAG = "Detail";
     private static final String DEVICES_ATTR = "devices";
     private static final String END_DISPLAY_TIME_ATTR = "end_display";
     private static final String END_TIME_ATTR = "end";
@@ -171,7 +172,11 @@
                                     parser.nextTag();
                                 } else {
                                     test.setReportLog(ReportLog.parse(parser));
-                                    parser.nextTag();
+                                    // Details are optional; parser is at next tag if report log
+                                    // does not have details.
+                                    if (parser.getName().equals(DETAIL_TAG)) {
+                                        parser.nextTag();
+                                    }
                                 }
                             }
                             parser.require(XmlPullParser.END_TAG, NS, TEST_TAG);
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
index 90ab764..51ed3ff 100644
--- a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
index 101602a..acf5cb6 100644
--- a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index a2ef1f3..ad00adb 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -36,6 +36,10 @@
  * Tests that verify installing of various split APKs from host side.
  */
 public class SplitTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    static final String PKG_NO_RESTART = "com.android.cts.norestart";
+    static final String APK_NO_RESTART_BASE = "CtsNoRestartBase.apk";
+    static final String APK_NO_RESTART_FEATURE = "CtsNoRestartFeature.apk";
+
     static final String PKG = "com.android.cts.splitapp";
     static final String CLASS = ".SplitAppTest";
 
@@ -110,6 +114,7 @@
         super.tearDown();
 
         getDevice().uninstallPackage(PKG);
+        getDevice().uninstallPackage(PKG_NO_RESTART);
     }
 
     public void testSingleBase() throws Exception {
@@ -279,6 +284,18 @@
         // TODO: flesh out this test
     }
 
+    public void testFeatureWithoutRestart() throws Exception {
+        new InstallMultiple().addApk(APK).run();
+        new InstallMultiple().addApk(APK_NO_RESTART_BASE).run();
+        runDeviceTests(PKG, CLASS, "testBaseInstalled");
+        new InstallMultiple()
+                .addArg("--dont-kill")
+                .inheritFrom(PKG_NO_RESTART)
+                .addApk(APK_NO_RESTART_FEATURE)
+                .run();
+        runDeviceTests(PKG, CLASS, "testFeatureInstalled");
+    }
+
     /**
      * Verify that installing a new version of app wipes code cache.
      */
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk b/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
new file mode 100644
index 0000000..69d3b4a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2016 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_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := CtsNoRestartBase
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+
+################################################
+# Build the feature split
+
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(LOCAL_PATH)/feature/Android.mk
+endif
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/NoRestartApp/AndroidManifest.xml
new file mode 100644
index 0000000..7140333
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.cts.norestart"
+    tools:ignore="MissingVersion" >
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="23" />
+
+    <application
+        tools:ignore="AllowBackup,MissingApplicationIcon" >
+        <activity
+            android:name=".NoRestartActivity"
+            android:launchMode="singleTop" >
+            <intent-filter>
+                <action android:name="com.android.cts.norestart.START" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
new file mode 100644
index 0000000..204275b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2016 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_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := CtsNoRestartFeature
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp
+featureOf := CtsNoRestartBase
+featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk
+$(localRStamp): $(featureOfApk)
+LOCAL_APK_LIBRARIES := $(featureOf)
+LOCAL_AAPT_FLAGS += --feature-of $(featureOfApk)
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/AndroidManifest.xml
new file mode 100644
index 0000000..b2fa3e8
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.cts.norestart"
+    split="feature"
+    tools:ignore="MissingVersion" >
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="23" />
+
+    <application
+        android:allowBackup="false"
+        tools:ignore="MissingApplicationIcon" >
+        <activity
+            android:name=".feature.NoRestartFeatureActivity"  >
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/res/layout/no_restart_feature_activity.xml b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/res/layout/no_restart_feature_activity.xml
new file mode 100644
index 0000000..a5f8812
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/res/layout/no_restart_feature_activity.xml
@@ -0,0 +1,32 @@
+<!-- Copyright (C) 2016 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="16dp"
+    android:paddingLeft="16dp"
+    android:paddingRight="16dp"
+    android:paddingTop="16dp"
+    android:orientation="vertical"
+    tools:context="com.android.cts.norestart.NoRestartFeatureActivity" >
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/no_restart_feature_text" />
+
+</LinearLayout>
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/res/values/strings.xml
new file mode 100644
index 0000000..1fb1db3
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<resources>
+    <string name="no_restart_feature_text">Hello feature!</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/src/com/android/cts/norestart/feature/NoRestartFeatureActivity.java b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/src/com/android/cts/norestart/feature/NoRestartFeatureActivity.java
new file mode 100644
index 0000000..40f8259
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/src/com/android/cts/norestart/feature/NoRestartFeatureActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 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.norestart.feature;
+
+import com.android.cts.norestart.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class NoRestartFeatureActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.no_restart_feature_activity);
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/res/layout/no_restart_activity.xml b/hostsidetests/appsecurity/test-apps/NoRestartApp/res/layout/no_restart_activity.xml
new file mode 100644
index 0000000..60ab817
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/res/layout/no_restart_activity.xml
@@ -0,0 +1,32 @@
+<!-- Copyright (C) 2016 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="16dp"
+    android:paddingLeft="16dp"
+    android:paddingRight="16dp"
+    android:paddingTop="16dp"
+    android:orientation="vertical"
+    tools:context="com.android.cts.norestart.NoRestartActivity" >
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/no_restart_text" />
+
+</LinearLayout>
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/NoRestartApp/res/values/strings.xml
new file mode 100644
index 0000000..5240150
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<resources>
+    <string name="no_restart_text">Hello, world!</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/src/com/android/cts/norestart/NoRestartActivity.java b/hostsidetests/appsecurity/test-apps/NoRestartApp/src/com/android/cts/norestart/NoRestartActivity.java
new file mode 100644
index 0000000..26d5712
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/src/com/android/cts/norestart/NoRestartActivity.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 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.norestart;
+
+import com.android.cts.norestart.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class NoRestartActivity extends Activity {
+    private int mCreateCount;
+    private int mNewIntentCount;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.no_restart_activity);
+        mCreateCount++;
+        sendBroadcast();
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        mNewIntentCount++;
+        sendBroadcast();
+    }
+
+    private void sendBroadcast() {
+        final Intent intent = new Intent("com.android.cts.norestart.BROADCAST");
+        intent.putExtra("CREATE_COUNT", mCreateCount);
+        intent.putExtra("NEW_INTENT_COUNT", mNewIntentCount);
+        sendBroadcast(intent);
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/res/values/values.xml b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/values.xml
index 3118fde..ecb7eae 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/res/values/values.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/values.xml
@@ -19,6 +19,7 @@
 
     <string name="my_string1">blue</string>
     <string name="my_string2">purple</string>
+    <string name="no_restart_text">Hello world!</string>
 
     <string-array name="my_string_array">
         <item>@string/my_string1</item>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
index c5f0fd0..7a693e8 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
@@ -19,8 +19,10 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -33,6 +35,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.os.ConditionVariable;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
@@ -305,6 +308,50 @@
         }
     }
 
+    public void testBaseInstalled() throws Exception {
+        final ConditionVariable cv = new ConditionVariable();
+        final BroadcastReceiver r = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                assertEquals(1, intent.getIntExtra("CREATE_COUNT", -1));
+                assertEquals(0, intent.getIntExtra("NEW_INTENT_COUNT", -1));
+                cv.open();
+            }
+        };
+        final IntentFilter filter = new IntentFilter("com.android.cts.norestart.BROADCAST");
+        getContext().registerReceiver(r, filter);
+        final Intent i = new Intent("com.android.cts.norestart.START");
+        i.addCategory(Intent.CATEGORY_DEFAULT);
+        getContext().startActivity(i);
+        assertTrue(cv.block(2000L));
+        getContext().unregisterReceiver(r);
+    }
+
+    /**
+     * Tests a running activity remains active while a new feature split is installed.
+     * <p>
+     * Prior to running this test, the activity must be started. That is currently
+     * done in {@link #testBaseInstalled()}.
+     */
+    public void testFeatureInstalled() throws Exception {
+        final ConditionVariable cv = new ConditionVariable();
+        final BroadcastReceiver r = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                assertEquals(1, intent.getIntExtra("CREATE_COUNT", -1));
+                assertEquals(1, intent.getIntExtra("NEW_INTENT_COUNT", -1));
+                cv.open();
+            }
+        };
+        final IntentFilter filter = new IntentFilter("com.android.cts.norestart.BROADCAST");
+        getContext().registerReceiver(r, filter);
+        final Intent i = new Intent("com.android.cts.norestart.START");
+        i.addCategory(Intent.CATEGORY_DEFAULT);
+        getContext().startActivity(i);
+        assertTrue(cv.block(2000L));
+        getContext().unregisterReceiver(r);
+    }
+
     public void testFeatureApi() throws Exception {
         final Resources r = getContext().getResources();
         final PackageManager pm = getContext().getPackageManager();
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index 1944444..e1c42b1 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -47,7 +47,8 @@
         </receiver>
 
         <activity
-            android:name="com.android.cts.deviceowner.KeyManagementActivity" />
+            android:name="com.android.cts.deviceowner.KeyManagementActivity"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
 
         <activity
             android:name="com.android.cts.deviceowner.LockTaskUtilityActivity" />
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf b/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf
new file mode 100644
index 0000000..c27a473
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf
@@ -0,0 +1,156 @@
+# OpenSSL root CA configuration file.
+# Copy to `/root/ca/openssl.cnf`.
+
+[ ca ]
+# `man ca`
+
+[ RootCA ]
+# Directory and file locations.
+dir               = ./rootca
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+# The root key and root certificate.
+private_key       = $dir/private/ca.key.pem
+certificate       = $dir/certs/ca.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/ca.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_strict
+
+[ IntermediateCA ]
+# Directory and file locations.
+dir               = ./intermediate
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+# The root key and root certificate.
+private_key       = $dir/private/intermediate.key.pem
+certificate       = $dir/certs/intermediate.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/ca.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_strict
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName             = match
+stateOrProvinceName     = match
+organizationName        = match
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits        = 4096
+distinguished_name  = req_distinguished_name
+string_mask         = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md          = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions     = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName                     = Country Name (2 letter code)
+stateOrProvinceName             = State or Province Name
+0.organizationName              = Organization Name
+organizationalUnitName          = Organizational Unit Name
+commonName                      = Common Name
+
+# Optionally, specify some defaults.
+countryName_default             = GB
+stateOrProvinceName_default     = England
+0.organizationName_default      = Google UK
+organizationalUnitName_default  = AfW
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh b/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh
new file mode 100755
index 0000000..8b0639f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+#
+# Generates:
+#  - user-cert-chain.crt
+#  - user-cert-chain.key
+#
+
+set -e
+
+WORKDIR='temp'
+
+mkdir "$WORKDIR"
+cp ca.conf "$WORKDIR/"
+pushd "$WORKDIR"
+
+## Generate root CA
+mkdir -p rootca/{certs,crl,newcerts,private}
+pushd rootca
+touch index.txt
+echo '1000' > serial
+openssl req \
+    -config ../ca.conf \
+    -new \
+    -x509 \
+    -days 7300 \
+    -sha256 \
+    -extensions v3_ca \
+    -keyout private/ca.key.pem \
+    -out certs/ca.cert.pem
+popd
+
+## Generate Intermediate CA
+mkdir intermediate intermediate/{certs,crl,csr,newcerts,private}
+touch intermediate/index.txt
+
+echo '1000' > intermediate/serial
+echo '1000' > intermediate/crlnumber
+
+openssl req \
+    -config ca.conf \
+    -new \
+    -sha256 \
+    -keyout intermediate/private/intermediate.key.pem \
+    -out intermediate/csr/intermediate.csr.pem
+
+openssl ca \
+    -config ca.conf \
+    -name RootCA \
+    -extensions v3_intermediate_ca \
+    -days 3650 \
+    -notext \
+    -md sha256 \
+    -in intermediate/csr/intermediate.csr.pem \
+    -out intermediate/certs/intermediate.cert.pem
+
+## Generate client cert
+openssl req \
+    -config ca.conf \
+    -newkey rsa:1024 \
+    -keyout user.key.pem \
+    -nodes \
+    -days 3650 \
+    -out user.csr.pem
+
+openssl ca \
+    -config ca.conf \
+    -name IntermediateCA \
+    -extensions usr_cert \
+    -days 365 \
+    -notext \
+    -md sha256 \
+    -in user.csr.pem \
+    -out user.cert.pem
+
+popd # WORKDIR
+
+## Convert client cert to acceptable form
+cat \
+    "$WORKDIR"/user.cert.pem \
+    "$WORKDIR"/intermediate/certs/intermediate.cert.pem \
+    "$WORKDIR"/rootca/certs/ca.cert.pem \
+    > user-cert-chain.crt
+
+openssl pkcs8 \
+    -topk8 \
+    -nocrypt \
+    -inform PEM \
+    -outform DER \
+    -in "$WORKDIR"/user.key.pem \
+    -out user-cert-chain.key
+
+rm -r "$WORKDIR"
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt
new file mode 100644
index 0000000..72a86e3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt
@@ -0,0 +1,96 @@
+-----BEGIN CERTIFICATE-----
+MIIFLzCCAxegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMCR0Ix
+EDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwD
+QWZ3MSEwHwYDVQQDDBhBZlcgVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTYwMzE4
+MTcxMzA4WhcNMTcwMzI4MTcxMzA4WjCBiDELMAkGA1UEBhMCR0IxEDAOBgNVBAgM
+B0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwDQWZ3MSUwIwYD
+VQQDDBxVc2VyMDAgdW5kZXIgaW50ZXJtZWRpYXRlIENBMR4wHAYJKoZIhvcNAQkB
+Fg90ZXN0QGdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC8W+PUeNVDIy6GSeTVjN9JSkYxcsupFq9AOUma0R+7z9EGuZBURZprgbrN7c2q
+RQnlSBZTC9fRMkXZ6LImWoY5GqS3NcbkJbUlA+UeK2uJXQQfjTO7bYDslvudX+8y
+WfYrR71DLpIFgDkxQAWGywMzNTR6TEmPy1qBGIFYohGqZkQoTS//s/iEEKDSsbPr
+mkTrf4lDAc8cgnmUPFPkN1Lr4ITkvhmEHQjJTcS+Qjeotlt+ss5vrmlqopFkCbI9
+7uC6RQDI0PvP9achzBsTUi0vNsGg45luCJhNrDu6s4NpnusKIVAoJPSJdion2yoD
+3Dp8LX/ueGNbP64LY6qmDWDlAgMBAAGjgcUwgcIwCQYDVR0TBAIwADARBglghkgB
+hvhCAQEEBAMCBaAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2VuZXJhdGVkIENs
+aWVudCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUSp7kS1On3b7MdMstDVPCNkHm/EUw
+HwYDVR0jBBgwFoAUdejD6Fb3X8ZHOCKMWe5XwukxBDswDgYDVR0PAQH/BAQDAgXg
+MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQsFAAOC
+AgEAXIOVhMjxbpO1uxe1MnyIsTrl0ajPlkn+4qWLwjXzUQ6TcE2Ow91AMcYs5siq
+UBplZyNYNBOhX8TZLNy7jJ/REwj65Qa/y0TcDucpGhtT9l1JIJCdEpPoymyiM18C
+NktXDyaw+DFkWC0a5oUhjk4UuzTfHkSVMKjZUnRPPiwL2gl9zEgS8qVI3ew4JjdP
+KCYGy/1B+61EE5vCP8GAByeKgtgnh4sVZnsKYQZzjwwUGL1uXQtazPs04qTUw3IK
+YvoOyNsXB4gcp2u4DXv2roVI36DQM5ZGenS9MViTeblg5vkZgy8xsktHyDGDlNe6
+cPw5OgyxDo4nr6TY4SX9eankantPMx7498n390B4lYAgBj4Cz4QaXM1IGN3JVF5J
+EEKqGkLpOYMRNZ4qPFhMknDZgHljjgFlcXGwtXtugCzQ5ldwkFb9qZeB5lQn1Aw0
+PthcDdGp/KCtHC5jF+BjlQITt0tVqJ4+SAdHyF53H+ScoINFul89m32pgvJjI/0k
+c0tidvXNPNodbJCqHmc917DryVJGXbxp+BqxTQ0a7e9K/WA4MnRKPfBTTeDq/j+w
+6B/rLd0bhMrPDi6a/1w97PqfAbS9TlkpnK8Gj4pN+ZOEEF0j0DtDRbb+CfJX14fR
+2R96mEfCeSbCuxLcbwdG1OUQM8GKlIcYfWIp0KjICxRKaDU=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFojCCA4qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwXDELMAkGA1UEBhMCR0Ix
+EDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwD
+QWZXMRkwFwYDVQQDDBBBZncgVGVzdCBSb290IENBMB4XDTE2MDMxODE3MDQ1N1oX
+DTI2MDMxNjE3MDQ1N1owZDELMAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQx
+EjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwDQWZ3MSEwHwYDVQQDDBhBZlcg
+VGVzdCBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCZbYchy2Fry9nJuu2YEp2P13lIbyWu0FXF8qTus8Vp/25LyXDjBiDXZUlY
+PL32PY0PRbBQjm7tm/WNqXw8S7gw+5XXpY+XNCd/ygyIZhMdxPm7nqYsEtZDFViL
+ct/QJNAKILFejZQOfRSeyxeINprL+EjFHecA6KtruZULzJE0u0UGTgs5h9HbqhH7
+LbZ8iiE/TfG6kflUI2kAPxGiRpIyerYoVjp3Ta5026T+aoc6VyNnSYiZULgYLoL8
+P8x19G3Pplqf4U5bUyKtRtnPWOvM9iYphxsVuTc8rRpZGcMKhdL4gGLQpdruIZ43
+gvGMq4Kt2xVJExBOKMg3j3x52j1XtOcad/nz7ncak/6ElTd0gfhFgt9PwAfQZ32b
+BL3Zlcb+7Pvtv14xAWNHy5cMyn7UDzIsy/yqWLvJSfkZViU0vPuokXMKZIyzv73V
+4N9qXQAWXNz4HwgWy35rB1sirgMxLdWCpHrVeh/DzSrWZ/MtJIC9Ac1jTAuI6F1u
+b7dRRujWpcr57ReKDXXJzM83JQnENJQ3gAHrY8qTkGz7NLa7DsyzPdKOC7vZ0+Ed
+VMvn+c2AMWrwkRpn9JlU5bd2BN7D6UWGLTdzSN9QH7n7sXmQNAo/M7Lr9baxKZNY
+aU5DORVjnGvITZDHYiw9OuakWZUZATF+TTInKEasF131r9q9ZwIDAQABo2YwZDAd
+BgNVHQ4EFgQUdejD6Fb3X8ZHOCKMWe5XwukxBDswHwYDVR0jBBgwFoAUV4EHHOi0
+AqQIj4IMjPEFW3fVS8QwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC
+AYYwDQYJKoZIhvcNAQELBQADggIBACs0qS3EXymo1VgBInR9GrzvUq1gC/d3ohSG
+iB3x2zfqfQ4D0eiYADcCdXTPIwPtm8P8woK5QsRV/MCklqyvgVpRHFQe1uOAZJ7X
+Ud6hx9CCye0QkEoy+JDeVdPeFFf1b8S/daxLXUVbCKSTA+z8YLPRSEFi2d3cOwpx
+WPlkfLSwP6DfODicmPNd1V/qB/fevlmfRB6UKquT+v9xWyQqu4aa6F6xGWYWmc+1
+E/MB/oEOizJVv8VVETqMk8/xFPrMk28foI8ohrLkstSx8gH+oII1Ud1k1XoMMqqU
+Ge656Tr85Di5WfacMdKUommOEKQYRiic6ikcNEAVVNOHlOtw08ua7g1k1G/dwcj0
+DCF2WmWzdAMwST0AH/RPa+i9cX8f/yS15OUP7ncSaI7/ChGT3EBzP+bqxeXFOCNH
+0yNLk4tNLIzNwnKXGTfSbKMTYOZ3ngAiR4w3ro/LJhe2z03MOawxoiIosTc9UwKA
+YJ3nYHYw8/EJCKPth6yrUU3gU1V0vyaBy34y4xuha3oWnbc53vm1cv4BINwmuAms
+ASQpqCiGp2ZaalNu87xCnWE3HA4S3+0U3dsFJXdPdQt/cDzX+kDzojWeHmECp6mn
+GodmmPbEBqzDckMaM9CvSAp8NyZuO8hrOSoGTdxQtP1w3waOeM4zLYd7aBYUfefL
+36OoziEN
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFnjCCA4agAwIBAgIJANLdX1zcxUSUMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV
+BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMRIwEAYDVQQKDAlHb29nbGUgVUsxDDAK
+BgNVBAsMA0FmVzEZMBcGA1UEAwwQQWZ3IFRlc3QgUm9vdCBDQTAeFw0xNjAzMTgx
+NzAxMDBaFw0zNjAzMTMxNzAxMDBaMFwxCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdF
+bmdsYW5kMRIwEAYDVQQKDAlHb29nbGUgVUsxDDAKBgNVBAsMA0FmVzEZMBcGA1UE
+AwwQQWZ3IFRlc3QgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBANFyOD/BIGV4iHSGDrp1ajvp+00098dn+p1cqlMHMrWUjnqzcMdOVmeqSaQ/
+EkOlAIsdcl1yb+oo3DhomIzX/B2lTQSOSLDmthIgmu0hfk/gAiqLdA8/L2F9m64N
+9x4+72xscN3MxzvjKGUBgPDmRfR9Tp347j42HUCjmF5sTa7DzGMrU7I3gCmi7B3D
+zbkgdTwpucH2JDqHQPv+7PLaNyuZNEmiXM76DPyMypxMrtGrq/FDVJ7JwF+cSwbY
+WVfzbmOfHG7g6hRw7Bap/NNjcdtP09hRPG/g2WDy4z0Ay8MTZVe95EHTsyeR+kpv
+0f60eUI0cV7EovbLmp10I3RdsxbWTjbeFmNjM7WmmmsFRzA1jMlFGil/po4mJvMF
+Bcqbi4kUhQ49F4tRUlHRG1b/up71tDuzToF0YmN9GHkf/kt7/noVTYdEsm4RwaeF
+mhoaTMFaNaHGTHSyqroqbBCqlkfTqB1Cqw1weGqV6bGfaYpCJGx5vXmr06mh5dwo
+zvpyHQKCQu96a0G81T526RtVeA4QR89ELa0JSBpWR9MqVZKBte9AgS5vlF0386uM
+vcKC3zJ4srv1YrTOmMkLktNJHsyfLQgb70RdHR38hDEwKaq6VDWiewKDhsWAI5SJ
+wRgjAYspsNUVahDWvpXq/bRGM3JTW+QxiR22vgEitvKeIysLAgMBAAGjYzBhMB0G
+A1UdDgQWBBRXgQcc6LQCpAiPggyM8QVbd9VLxDAfBgNVHSMEGDAWgBRXgQcc6LQC
+pAiPggyM8QVbd9VLxDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAN
+BgkqhkiG9w0BAQsFAAOCAgEAjo/Fj7iTOr1/nTvZpeaon0/xY4D+Hf83FW/4yASZ
+Et0ITa510zIi8rIVvlaR1xdbXLYxHgdtm4vQtKZStwOBdwj+4VZrb9WgwQyBCYU5
+RqK387oMUeZdfsh9m2nqM8buYls3mldv34XUg8y1oytx6GDdC7NKz6PLNpIVkj5F
+aBnyfh43FsXHkzAy0nfkdE2mqfhQ4CD9Zkm9fJcX0inEmcspM5G8ba16uESZDqUS
+oJc1bgNtW64fL7pOtVfHDIJqKf/G/iIq1lk33gv5/4z6Z8e7fYVm1JabUUd9rZ6t
+cjXXFqkA7SkcXTs829/gaXQQv2FARt7g70UxJmNN0MCKfYnKM4dKddi934mTWrOI
+eLe0u3OAa1wZaHggJJXgRxMx/acWnGfersTpsAB1XG74XTSXHV7zHHnNWXjQ+gu0
+N4RAkQFMYWqp6KoHgQrdQfLPcaw0wc+ZMJj35z50b4ab+Bygthx3W+v/MiMFK9Wv
+/AsQCGslDcGWbFCYP7IvHDfownIFGefMnOm41NKWus9z6HoEUmfJiiSSVxECDT/2
+fE7M+sQovdrlHx7ru/fO6PP+6ocUE1afY6cHUzE0Dhv6xMcdvwL7COGd5ZU1bqAQ
+TqbePM5Kpk1ytkigdixzMDz/HFum0fdGfc/59Ll+f6+uHAX5NpOJZkBHBCWAoCeX
+bsg=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key
new file mode 100644
index 0000000..8bb399e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key
Binary files differ
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementActivity.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementActivity.java
index c108d24..fda124f 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementActivity.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementActivity.java
@@ -17,14 +17,6 @@
 package com.android.cts.deviceowner;
 
 import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
 
 public class KeyManagementActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        finish();
-    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index 5d6d7fb..219dfc2 100755
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -27,21 +27,29 @@
 import android.test.ActivityInstrumentationTestCase2;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.security.cert.Certificate;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.AssetManager;
 
 public class KeyManagementTest extends ActivityInstrumentationTestCase2<KeyManagementActivity> {
 
@@ -126,6 +134,38 @@
         assertGranted(withhold, false);
     }
 
+    public void testCanInstallCertChain() throws Exception {
+        // Use assets/generate-client-cert-chain.sh to regenerate the client cert chain.
+        final PrivateKey privKey = loadPrivateKeyFromAsset("user-cert-chain.key");
+        final Collection<Certificate> certs = loadCertificatesFromAsset("user-cert-chain.crt");
+        final Certificate[] certChain = certs.toArray(new Certificate[certs.size()]);
+        final String alias = "com.android.test.clientkeychain";
+        // Some sanity check on the cert chain
+        assertTrue(certs.size() > 1);
+        for (int i = 1; i < certs.size(); i++) {
+            certChain[i - 1].verify(certChain[i].getPublicKey());
+        }
+
+        // Install keypairs.
+        assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, certChain, alias, true));
+        try {
+            // Verify only the requested key was actually granted.
+            assertGranted(alias, true);
+
+            // Verify the granted key is actually obtainable in PrivateKey form.
+            assertEquals(KeyChain.getPrivateKey(getActivity(), alias).getAlgorithm(), "RSA");
+
+            // Verify the certificate chain is correct
+            X509Certificate[] returnedCerts = KeyChain.getCertificateChain(getActivity(), alias);
+            assertTrue(Arrays.equals(certChain, returnedCerts));
+        } finally {
+            // Delete both keypairs.
+            assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias));
+        }
+        // Verify they're actually gone.
+        assertGranted(alias, false);
+    }
+
     public void testGrantsDoNotPersistBetweenInstallations() throws Exception {
         final String alias = "com.android.test.persistent-key-1";
         final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA");
@@ -200,6 +240,35 @@
                 new ByteArrayInputStream(cert));
     }
 
+    private Collection<Certificate> loadCertificatesFromAsset(String assetName) {
+        try {
+            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            AssetManager am = getActivity().getAssets();
+            InputStream is = am.open(assetName);
+            return (Collection<Certificate>) certFactory.generateCertificates(is);
+        } catch (IOException | CertificateException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private PrivateKey loadPrivateKeyFromAsset(String assetName) {
+        try {
+            AssetManager am = getActivity().getAssets();
+            InputStream is = am.open(assetName);
+            ByteArrayOutputStream output = new ByteArrayOutputStream();
+            int length;
+            byte[] buffer = new byte[4096];
+            while ((length = is.read(buffer, 0, buffer.length)) != -1) {
+              output.write(buffer, 0, length);
+            }
+            return getPrivateKey(output.toByteArray(), "RSA");
+        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
     private class KeyChainAliasFuture implements KeyChainAliasCallback {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private String mChosenAlias = null;
@@ -224,5 +293,5 @@
             assertTrue("Chooser timeout", mLatch.await(KEYCHAIN_TIMEOUT_MINS, TimeUnit.MINUTES));
             return mChosenAlias;
         }
-    };
+    }
 }
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
index f2445c0..54892de 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -31,6 +31,7 @@
 import java.util.Objects;
 
 import static android.server.cts.ActivityManagerTestBase.FREEFORM_WORKSPACE_STACK_ID;
+import static android.server.cts.ActivityManagerTestBase.PINNED_STACK_ID;
 import static android.server.cts.StateLogger.log;
 
 /** Combined state of the activity manager and window manager. */
@@ -349,7 +350,8 @@
                         }
 
                         if (aStackBounds.getWidth() >= aTaskMinWidth
-                                && aStackBounds.getHeight() >= aTaskMinHeight) {
+                                && aStackBounds.getHeight() >= aTaskMinHeight
+                                || stackId == PINNED_STACK_ID) {
                             // Bounds are not smaller then minimal possible, so stack and task
                             // bounds must be equal.
                             assertEquals("Task bounds must be equal to stack bounds taskId="
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
index 0a01d6d..24b9fa9 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
@@ -117,11 +117,11 @@
     }
 
     public void testTranslucentActivityOverDockedStack() throws Exception {
-        mDevice.executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
         launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
-        launchActivityInDockStack(TRANSLUCENT_ACTIVITY_NAME);
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME},
-                false /* compareTaskAndStackBounds */);
+        launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        launchActivityInStack(TRANSLUCENT_ACTIVITY_NAME, DOCKED_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME,
+                TRANSLUCENT_ACTIVITY_NAME}, false /* compareTaskAndStackBounds */);
         mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID);
         mAmWmState.assertContainsStack("Must contain fullscreen stack",
                 FULLSCREEN_WORKSPACE_STACK_ID);
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
index 9e1e2cc..35ea407 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -194,7 +194,7 @@
 
     public void testResizeDockedStack() throws Exception {
         launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
-        launchActivityToSide(TEST_ACTIVITY_NAME);
+        launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
         resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME},
                 false /* compareTaskAndStackBounds */);
@@ -215,7 +215,7 @@
                 mAmWmState.getWmState().getStack(FULLSCREEN_WORKSPACE_STACK_ID).getBounds();
 
         moveActivityToDockStack(TEST_ACTIVITY_NAME);
-        launchActivityToSide(NO_RELAUNCH_ACTIVITY_NAME);
+        launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
 
         mAmWmState.computeState(mDevice,
                 new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
index 8eb0361..e56c32f 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
@@ -33,6 +33,7 @@
 
 import static android.server.cts.ActivityManagerTestBase.HOME_STACK_ID;
 import static android.server.cts.StateLogger.log;
+import static android.server.cts.StateLogger.logE;
 
 class ActivityManagerState {
     private static final String DUMPSYS_ACTIVITY_ACTIVITIES = "dumpsys activity activities";
@@ -96,16 +97,16 @@
         }
 
         if (mStacks.isEmpty()) {
-            log("No stacks found...");
+            logE("No stacks found...");
         }
         if (mFocusedStackId == -1) {
-            log("No focused stack found...");
+            logE("No focused stack found...");
         }
         if (mFocusedActivityRecord == null) {
-            log("No focused activity found...");
+            logE("No focused activity found...");
         }
         if (mResumedActivities.isEmpty()) {
-            log("No resumed activities found...");
+            logE("No resumed activities found...");
         }
     }
 
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java
index e330a9d..4c4748a 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java
@@ -98,6 +98,7 @@
     protected ActivityAndWindowManagersState mAmWmState = new ActivityAndWindowManagersState();
 
     private int mInitialAccelerometerRotation;
+    private int mUserRotation;
 
     @Override
     protected void setUp() throws Exception {
@@ -106,6 +107,7 @@
         // Get the device, this gives a handle to run commands and install APKs.
         mDevice = getDevice();
         mInitialAccelerometerRotation = getAccelerometerRotation();
+        mUserRotation = getUserRotation();
     }
 
     @Override
@@ -114,6 +116,7 @@
         try {
             mDevice.executeShellCommand(AM_FORCE_STOP_TEST_PACKAGE);
             setAccelerometerRotation(mInitialAccelerometerRotation);
+            setUserRotation(mUserRotation);
             // Remove special stacks.
             mDevice.executeShellCommand(AM_REMOVE_STACK + PINNED_STACK_ID);
             mDevice.executeShellCommand(AM_REMOVE_STACK + DOCKED_STACK_ID);
@@ -167,8 +170,10 @@
         CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
         final String output = outputReceiver.getOutput();
+        final Pattern activityPattern = Pattern.compile("(.*) " + getWindowName(name) + " (.*)");
         for (String line : output.split("\\n")) {
-            if (line.contains(name)) {
+            Matcher matcher = activityPattern.matcher(line);
+            if (matcher.matches()) {
                 for (String word : line.split("\\s+")) {
                     if (word.startsWith(TASK_ID_PREFIX)) {
                         final String withColon = word.split("=")[1];
@@ -224,13 +229,13 @@
 
     protected void setDeviceRotation(int rotation) throws DeviceNotAvailableException {
         setAccelerometerRotation(0);
-        runCommandAndPrintOutput("settings put system user_rotation " + rotation);
+        setUserRotation(rotation);
     }
 
     private int getAccelerometerRotation() throws DeviceNotAvailableException {
         final String rotation =
                 runCommandAndPrintOutput("settings get system accelerometer_rotation");
-        return Integer.valueOf(rotation.trim());
+        return Integer.parseInt(rotation.trim());
     }
 
     private void setAccelerometerRotation(int rotation) throws DeviceNotAvailableException {
@@ -238,6 +243,25 @@
                 "settings put system accelerometer_rotation " + rotation);
     }
 
+    private int getUserRotation() throws DeviceNotAvailableException {
+        final String rotation =
+                runCommandAndPrintOutput("settings get system user_rotation").trim();
+        if ("null".equals(rotation)) {
+            return -1;
+        }
+        return Integer.parseInt(rotation);
+    }
+
+    private void setUserRotation(int rotation) throws DeviceNotAvailableException {
+        if (rotation == -1) {
+            runCommandAndPrintOutput(
+                    "settings delete system user_rotation");
+        } else {
+            runCommandAndPrintOutput(
+                    "settings put system user_rotation " + rotation);
+        }
+    }
+
     protected String runCommandAndPrintOutput(String command) throws DeviceNotAvailableException {
         final String output = mDevice.executeShellCommand(command);
         CLog.logAndDisplay(LogLevel.INFO, command);
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/StateLogger.java b/hostsidetests/services/activitymanager/src/android/server/cts/StateLogger.java
index 1266102..335f26c 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/StateLogger.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/StateLogger.java
@@ -19,6 +19,7 @@
 import com.android.tradefed.log.LogUtil.CLog;
 
 import static com.android.ddmlib.Log.LogLevel.INFO;
+import static com.android.ddmlib.Log.LogLevel.ERROR;
 
 /**
  * Util class to perform simple state logging.
@@ -32,4 +33,8 @@
             CLog.logAndDisplay(INFO, logText);
         }
     }
+
+    public static void logE(String logText) {
+        CLog.logAndDisplay(ERROR, logText);
+    }
 }
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
index ffa3b83..da346ac 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
@@ -32,6 +32,7 @@
 import java.util.regex.Matcher;
 
 import static android.server.cts.StateLogger.log;
+import static android.server.cts.StateLogger.logE;
 
 class WindowManagerState {
     private static final String DUMPSYS_WINDOWS_APPS = "dumpsys window apps";
@@ -105,13 +106,13 @@
         }
 
         if (mWindows.isEmpty()) {
-            log("No Windows found...");
+            logE("No Windows found...");
         }
         if (mFocusedWindow == null) {
-            log("No Focused Window...");
+            logE("No Focused Window...");
         }
         if (mFocusedApp == null) {
-            log("No Focused App...");
+            logE("No Focused App...");
         }
     }
 
diff --git a/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java b/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java
index 5325b29..3f91c20 100644
--- a/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java
+++ b/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java
@@ -32,6 +32,7 @@
     }
 
     public void testNotListening() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         assertTrue(waitFor("onDestroy"));
 
@@ -42,6 +43,7 @@
     }
 
     public void testRequestListening() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         assertTrue(waitFor("onDestroy"));
 
@@ -52,6 +54,7 @@
     }
 
     public void testClick() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         assertTrue(waitFor("onDestroy"));
 
diff --git a/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java b/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java
index 50d25e8..0ae861b 100644
--- a/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java
+++ b/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java
@@ -63,6 +63,7 @@
     protected void tearDown() throws Exception {
         super.tearDown();
 
+        if (!supportedHardware()) return;
         collapse();
         remTile();
         // Try to wait for a onTileRemoved.
@@ -122,4 +123,10 @@
     private void clearLogcat() throws DeviceNotAvailableException {
         getDevice().executeAdbCommand("logcat", "-c");
     }
+
+    protected boolean supportedHardware() throws DeviceNotAvailableException {
+        String features = getDevice().executeShellCommand("pm list features");
+        return !features.contains("android.hardware.type.television") &&
+               !features.contains("android.hardware.type.watch");
+    }
 }
diff --git a/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java b/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java
index 3c92918..0c06935 100644
--- a/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java
+++ b/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java
@@ -33,6 +33,7 @@
     }
 
     public void testAddTile() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         // Verify that the service starts up and gets a onTileAdded callback.
         assertTrue(waitFor("onCreate"));
@@ -41,6 +42,7 @@
     }
 
     public void testRemoveTile() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         // Verify that the service starts up and gets a onTileAdded callback.
         assertTrue(waitFor("onCreate"));
@@ -52,6 +54,7 @@
     }
 
     public void testListeningNotifications() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         assertTrue(waitFor("onDestroy"));
 
@@ -64,6 +67,7 @@
     }
 
     public void testListeningSettings() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         assertTrue(waitFor("onDestroy"));
 
@@ -76,6 +80,7 @@
     }
 
     public void testCantAddDialog() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         assertTrue(waitFor("onDestroy"));
 
@@ -93,6 +98,7 @@
     }
 
     public void testClick() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         // Wait for the tile to be added.
         assertTrue(waitFor("onTileAdded"));
@@ -114,6 +120,7 @@
     }
 
     public void testClickAndShowDialog() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         assertTrue(waitFor("onDestroy"));
 
@@ -132,6 +139,7 @@
     }
 
     public void testStartActivity() throws Exception {
+        if (!supportedHardware()) return;
         addTile();
         // Wait for the tile to be added.
         assertTrue(waitFor("onTileAdded"));
diff --git a/libs/deviceutil/src/android/cts/util/KeyEventUtil.java b/libs/deviceutil/src/android/cts/util/KeyEventUtil.java
new file mode 100644
index 0000000..4031adf
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/KeyEventUtil.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2016 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 android.cts.util;
+
+import android.app.Instrumentation;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+import java.lang.reflect.Field;
+
+/**
+ * Utility class to send KeyEvents to TextView bypassing the IME. The code is similar to functions
+ * in {@link Instrumentation} and {@link android.test.InstrumentationTestCase} classes. It uses
+ * {@link InputMethodManager#dispatchKeyEventFromInputMethod(View, KeyEvent)} to send the events.
+ * After sending the events waits for idle.
+ */
+public class KeyEventUtil {
+    private final Instrumentation mInstrumentation;
+
+    public KeyEventUtil(Instrumentation instrumentation) {
+        this.mInstrumentation = instrumentation;
+    }
+
+    /**
+     * Sends the key events corresponding to the text to the app being instrumented.
+     *
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param text The text to be sent. Null value returns immediately.
+     */
+    public final void sendString(final View targetView, final String text) {
+        if (text == null) {
+            return;
+        }
+
+        KeyEvent[] events = getKeyEvents(text);
+
+        if (events != null) {
+            for (int i = 0; i < events.length; i++) {
+                // We have to change the time of an event before injecting it because
+                // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
+                // time stamp and the system rejects too old events. Hence, it is
+                // possible for an event to become stale before it is injected if it
+                // takes too long to inject the preceding ones.
+                sendKey(targetView, KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(),
+                        0));
+            }
+        }
+    }
+
+    /**
+     * Sends a series of key events through instrumentation. For instance:
+     * sendKeys(view, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER).
+     *
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param keys The series of key codes.
+     */
+    public final void sendKeys(final View targetView, final int...keys) {
+        final int count = keys.length;
+
+        for (int i = 0; i < count; i++) {
+            try {
+                sendKeyDownUp(targetView, keys[i]);
+            } catch (SecurityException e) {
+                // Ignore security exceptions that are now thrown
+                // when trying to send to another app, to retain
+                // compatibility with existing tests.
+            }
+        }
+    }
+
+    /**
+     * Sends a series of key events through instrumentation. The sequence of keys is a string
+     * containing the key names as specified in KeyEvent, without the KEYCODE_ prefix. For
+     * instance: sendKeys(view, "DPAD_LEFT A B C DPAD_CENTER"). Each key can be repeated by using
+     * the N* prefix. For instance, to send two KEYCODE_DPAD_LEFT, use the following:
+     * sendKeys(view, "2*DPAD_LEFT").
+     *
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param keysSequence The sequence of keys.
+     */
+    public final void sendKeys(final View targetView, final String keysSequence) {
+        final String[] keys = keysSequence.split(" ");
+        final int count = keys.length;
+
+        for (int i = 0; i < count; i++) {
+            String key = keys[i];
+            int repeater = key.indexOf('*');
+
+            int keyCount;
+            try {
+                keyCount = repeater == -1 ? 1 : Integer.parseInt(key.substring(0, repeater));
+            } catch (NumberFormatException e) {
+                Log.w("ActivityTestCase", "Invalid repeat count: " + key);
+                continue;
+            }
+
+            if (repeater != -1) {
+                key = key.substring(repeater + 1);
+            }
+
+            for (int j = 0; j < keyCount; j++) {
+                try {
+                    final Field keyCodeField = KeyEvent.class.getField("KEYCODE_" + key);
+                    final int keyCode = keyCodeField.getInt(null);
+                    try {
+                        sendKeyDownUp(targetView, keyCode);
+                    } catch (SecurityException e) {
+                        // Ignore security exceptions that are now thrown
+                        // when trying to send to another app, to retain
+                        // compatibility with existing tests.
+                    }
+                } catch (NoSuchFieldException e) {
+                    Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
+                    break;
+                } catch (IllegalAccessException e) {
+                    Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Sends an up and down key events.
+     *
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param key The integer keycode for the event to be send.
+     */
+    public final void sendKeyDownUp(final View targetView, final int key) {
+        sendKey(targetView, new KeyEvent(KeyEvent.ACTION_DOWN, key));
+        sendKey(targetView, new KeyEvent(KeyEvent.ACTION_UP, key));
+    }
+
+    /**
+     * Sends a key event.
+     *
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param event KeyEvent to be send.
+     */
+    public final void sendKey(final View targetView, final KeyEvent event) {
+        validateNotAppThread();
+
+        long downTime = event.getDownTime();
+        long eventTime = event.getEventTime();
+        int action = event.getAction();
+        int code = event.getKeyCode();
+        int repeatCount = event.getRepeatCount();
+        int metaState = event.getMetaState();
+        int deviceId = event.getDeviceId();
+        int scancode = event.getScanCode();
+        int source = event.getSource();
+        int flags = event.getFlags();
+        if (source == InputDevice.SOURCE_UNKNOWN) {
+            source = InputDevice.SOURCE_KEYBOARD;
+        }
+        if (eventTime == 0) {
+            eventTime = SystemClock.uptimeMillis();
+        }
+        if (downTime == 0) {
+            downTime = eventTime;
+        }
+
+        final KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount,
+                metaState, deviceId, scancode, flags, source);
+
+        InputMethodManager imm = targetView.getContext().getSystemService(InputMethodManager.class);
+        imm.dispatchKeyEventFromInputMethod(targetView, newEvent);
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private KeyEvent[] getKeyEvents(final String text) {
+        KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+        return keyCharacterMap.getEvents(text.toCharArray());
+    }
+
+    private void validateNotAppThread() {
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            throw new RuntimeException(
+                    "This method can not be called from the main application thread");
+        }
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index 7da7d37..df48a61 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -84,12 +84,11 @@
         GestureDescription click = createClick(clickX, clickY);
         mService.runOnServiceSync(() -> mService.doDispatchGesture(click, mCallback, null));
         mCallback.assertGestureCompletes(GESTURE_COMPLETION_TIMEOUT);
-        waitForMotionEvents(3);
+        waitForMotionEvents(2);
 
-        assertEquals(3, mMotionEvents.size());
+        assertEquals(2, mMotionEvents.size());
         MotionEvent clickDown = mMotionEvents.get(0);
-        MotionEvent clickMove = mMotionEvents.get(1);
-        MotionEvent clickUp = mMotionEvents.get(2);
+        MotionEvent clickUp = mMotionEvents.get(1);
 
         assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
         assertEquals(0, clickDown.getActionIndex());
@@ -103,23 +102,13 @@
         assertEquals((float) clickYInsideView, clickDown.getY());
         assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
 
-        assertEquals(MotionEvent.ACTION_MOVE, clickMove.getActionMasked());
-        assertEquals(clickDown.getDownTime(), clickMove.getDownTime());
-        assertEquals(ViewConfiguration.getTapTimeout(),
-                clickMove.getEventTime() - clickMove.getDownTime());
-        assertEquals(0, clickMove.getActionIndex());
-        assertEquals(1, clickMove.getPointerCount());
-        assertEquals((float) clickXInsideView + 1, clickMove.getX());
-        assertEquals((float) clickYInsideView, clickMove.getY());
-        assertEquals(clickDown.getPointerId(0),
-                clickMove.getPointerId(0));
-
         assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
         assertEquals(clickDown.getDownTime(), clickUp.getDownTime());
-        assertEquals(clickMove.getEventTime(), clickUp.getEventTime());
+        assertEquals(ViewConfiguration.getTapTimeout(),
+                clickUp.getEventTime() - clickUp.getDownTime());
         assertTrue(clickDown.getEventTime() + ViewConfiguration.getLongPressTimeout()
                 > clickUp.getEventTime());
-        assertEquals((float) clickXInsideView + 1, clickUp.getX());
+        assertEquals((float) clickXInsideView, clickUp.getX());
         assertEquals((float) clickYInsideView, clickUp.getY());
     }
 
@@ -133,27 +122,20 @@
         mCallback.assertGestureCompletes(
                 ViewConfiguration.getLongPressTimeout() + GESTURE_COMPLETION_TIMEOUT);
 
-        waitForMotionEvents(3);
+        waitForMotionEvents(2);
         MotionEvent clickDown = mMotionEvents.get(0);
-        MotionEvent clickMove = mMotionEvents.get(1);
-        MotionEvent clickUp = mMotionEvents.get(2);
+        MotionEvent clickUp = mMotionEvents.get(1);
 
         assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
 
         assertEquals((float) clickXInsideView, clickDown.getX());
         assertEquals((float) clickYInsideView, clickDown.getY());
 
-        assertEquals(MotionEvent.ACTION_MOVE, clickMove.getActionMasked());
-        assertEquals(clickDown.getDownTime(), clickMove.getDownTime());
-        assertEquals((float) clickXInsideView + 1, clickMove.getX());
-        assertEquals((float) clickYInsideView, clickMove.getY());
-        assertEquals(clickDown.getPointerId(0), clickMove.getPointerId(0));
-
         assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
         assertTrue(clickDown.getEventTime() + ViewConfiguration.getLongPressTimeout()
                 <= clickUp.getEventTime());
         assertEquals(clickDown.getDownTime(), clickUp.getDownTime());
-        assertEquals((float) clickXInsideView + 1, clickUp.getX());
+        assertEquals((float) clickXInsideView, clickUp.getX());
         assertEquals((float) clickYInsideView, clickUp.getY());
     }
 
@@ -349,22 +331,17 @@
             assertTrue("Failed to reset", result.get());
         }
 
-        assertEquals(3, mMotionEvents.size());
+        assertEquals(2, mMotionEvents.size());
         MotionEvent clickDown = mMotionEvents.get(0);
-        MotionEvent clickMove = mMotionEvents.get(1);
-        MotionEvent clickUp = mMotionEvents.get(2);
+        MotionEvent clickUp = mMotionEvents.get(1);
 
         assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
         assertEquals((float) clickXInsideView, clickDown.getX(), TOUCH_TOLERANCE);
         assertEquals((float) clickYInsideView, clickDown.getY(), TOUCH_TOLERANCE);
         assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
 
-        assertEquals(MotionEvent.ACTION_MOVE, clickMove.getActionMasked());
-        assertEquals((float) clickXInsideView + 1, clickMove.getX(), TOUCH_TOLERANCE);
-        assertEquals((float) clickYInsideView, clickMove.getY(), TOUCH_TOLERANCE);
-
         assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
-        assertEquals((float) clickXInsideView + 1, clickUp.getX(), TOUCH_TOLERANCE);
+        assertEquals((float) clickXInsideView, clickUp.getX(), TOUCH_TOLERANCE);
         assertEquals((float) clickYInsideView, clickUp.getY(), TOUCH_TOLERANCE);
     }
 
@@ -450,7 +427,6 @@
     private GestureDescription createClick(int x, int y) {
         Path clickPath = new Path();
         clickPath.moveTo(x, y);
-        clickPath.lineTo(x + 1, y);
         GestureDescription.StrokeDescription clickStroke =
                 new GestureDescription.StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout());
         GestureDescription.Builder clickBuilder = new GestureDescription.Builder();
@@ -461,7 +437,6 @@
     private GestureDescription createLongClick(int x, int y) {
         Path clickPath = new Path();
         clickPath.moveTo(x, y);
-        clickPath.lineTo(x + 1, y);
         int longPressTime = ViewConfiguration.getLongPressTimeout();
 
         GestureDescription.StrokeDescription longClickStroke =
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
index b3fa9d2..234f66a 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
@@ -93,13 +93,11 @@
         }
     }
 
-    public void testCreateStroke_pathWithZeroLength_shouldThrow() {
-        Path zeroLengthPath = new Path();
-        zeroLengthPath.moveTo(0, 0);
-        zeroLengthPath.lineTo(0, 0);
+    public void testCreateStroke_withEmptyPath_shouldThrow() {
+        Path emptyPath = new Path();
         try {
-            new GestureDescription.StrokeDescription(zeroLengthPath, 0, NOMINAL_PATH_DURATION);
-            fail("Missing exception for stroke with path of zero length.");
+            new GestureDescription.StrokeDescription(emptyPath, 0, NOMINAL_PATH_DURATION);
+            fail("Missing exception for empty path.");
         } catch (IllegalArgumentException e) {
         }
     }
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index ea094ab..cc06ead 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -124,6 +124,9 @@
             <meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
         </service>
 
+        <service android:name="android.app.stubs.LocalForegroundService">
+        </service>
+
         <service android:name="android.app.stubs.LocalGrantedService"
              android:permission="android.app.stubs.permission.TEST_GRANTED">
             <intent-filter>
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundService.java b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
new file mode 100644
index 0000000..119b9f8
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 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 android.app.stubs;
+
+import android.app.Notification;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.cts.util.IBinderParcelable;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+import android.app.stubs.R;
+
+public class LocalForegroundService extends LocalService {
+
+    private static final String TAG = "LocalForegroundService";
+    private static final String EXTRA_COMMAND = "LocalForegroundService.command";
+
+    public static final int COMMAND_START_FOREGROUND = 1;
+    public static final int COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION = 2;
+    public static final int COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION = 3;
+    public static final int COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION = 4;
+    public static final int COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS = 5;
+
+    private int mNotificationId = 0;
+
+    @Override
+    public void onStart(Intent intent, int startId) {
+        super.onStart(intent, startId);
+
+        Context context = getApplicationContext();
+        int command = intent.getIntExtra(EXTRA_COMMAND, -1);
+
+        switch (command) {
+            case COMMAND_START_FOREGROUND:
+                mNotificationId ++;
+                Log.d(TAG, "Starting foreground using notification " + mNotificationId);
+                Notification notification = new Notification.Builder(context)
+                        .setContentTitle(getNotificationTitle(mNotificationId))
+                        .setSmallIcon(R.drawable.black)
+                        .build();
+                startForeground(mNotificationId, notification);
+                break;
+            case COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION:
+                Log.d(TAG, "Stopping foreground removing notification");
+                stopForeground(true);
+                break;
+            case COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION:
+                Log.d(TAG, "Stopping foreground without removing notification");
+                stopForeground(false);
+                break;
+            case COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS:
+                Log.d(TAG, "Stopping foreground removing notification using flags");
+                stopForeground(Service.STOP_FOREGROUND_REMOVE | Service.STOP_FOREGROUND_DETACH);
+                break;
+            case COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION:
+                Log.d(TAG, "Detaching foreground service notification");
+                stopForeground(Service.STOP_FOREGROUND_DETACH);
+                break;
+            default:
+                Log.e(TAG, "Unknown command: " + command);
+        }
+    }
+
+    public static Bundle newCommand(IBinder stateReceiver, int command) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(LocalService.REPORT_OBJ_NAME, new IBinderParcelable(stateReceiver));
+        bundle.putInt(EXTRA_COMMAND, command);
+        return bundle;
+    }
+
+    public static String getNotificationTitle(int id) {
+        return "I AM FOREGROOT #" + id;
+    }
+}
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 4842bb1..1d6d23d 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -16,8 +16,11 @@
 
 package android.app.cts;
 
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.stubs.ActivityTestsBase;
 import android.app.stubs.LocalDeniedService;
+import android.app.stubs.LocalForegroundService;
 import android.app.stubs.LocalGrantedService;
 import android.app.stubs.LocalService;
 import android.content.ComponentName;
@@ -30,15 +33,20 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
+import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.app.stubs.R;
 
 public class ServiceTest extends ActivityTestsBase {
+    private static final String TAG = "ServiceTest";
     private static final int STATE_START_1 = 0;
     private static final int STATE_START_2 = 1;
-    private static final int STATE_UNBIND = 2;
-    private static final int STATE_DESTROY = 3;
-    private static final int STATE_REBIND = 4;
-    private static final int STATE_UNBIND_ONLY = 5;
+    private static final int STATE_START_3 = 2;
+    private static final int STATE_UNBIND = 3;
+    private static final int STATE_DESTROY = 4;
+    private static final int STATE_REBIND = 5;
+    private static final int STATE_UNBIND_ONLY = 6;
     private static final int DELAY = 5000;
     private static final
         String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
@@ -47,6 +55,7 @@
     private Context mContext;
     private Intent mLocalService;
     private Intent mLocalDeniedService;
+    private Intent mLocalForegroundService;
     private Intent mLocalGrantedService;
     private Intent mLocalService_ApplicationHasPermission;
     private Intent mLocalService_ApplicationDoesNotHavePermission;
@@ -157,6 +166,82 @@
         waitForResultOrThrow(DELAY, "service to be destroyed");
     }
 
+    private NotificationManager getNotificationManager() {
+        NotificationManager notificationManager =
+                (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
+        return notificationManager;
+    }
+
+    private void sendNotififcation(int id, String title) {
+        Notification notification = new Notification.Builder(getContext())
+            .setContentTitle(title)
+            .setSmallIcon(R.drawable.black)
+            .build();
+        getNotificationManager().notify(id, notification);
+    }
+
+    private void cancelNotification(int id) {
+        getNotificationManager().cancel(id);
+    }
+
+    private void assertNotification(int id, String expectedTitle) {
+        String packageName = getContext().getPackageName();
+        String errorMessage = null;
+        for (int i = 1; i<=2; i++) {
+            errorMessage = null;
+            StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) {
+                    String actualTitle =
+                            sbn.getNotification().extras.getString(Notification.EXTRA_TITLE);
+                    if (expectedTitle.equals(actualTitle)) {
+                        return;
+                    }
+                    // It's possible the notification hasn't been updated yet, so save the error
+                    // message to only fail after retrying.
+                    errorMessage = String.format("Wrong title for notification #%d: "
+                            + "expected '%s', actual '%s'", id, expectedTitle, actualTitle);
+                    Log.w(TAG, errorMessage);
+                }
+            }
+            // Notification might not be rendered yet, wait and try again...
+            try {
+                Thread.sleep(DELAY);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+        }
+        if (errorMessage != null) {
+            fail(errorMessage);
+        }
+        fail("No notification with id " + id + " for package " + packageName);
+    }
+
+    private void assertNoNotification(int id) {
+        String packageName = getContext().getPackageName();
+        StatusBarNotification found = null;
+        for (int i = 1; i<=2; i++) {
+            found = null;
+            StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) {
+                    found = sbn;
+                    break;
+                }
+            }
+            if (found != null) {
+                // Notification might not be canceled yet, wait and try again...
+                try {
+                    Thread.sleep(DELAY);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }
+        assertNull("Found notification with id " + id + " for package " + packageName + ": "
+                + found, found);
+    }
+
     /**
      * test the service lifecycle, a service can be used in two ways:
      * 1  It can be started and allowed to run until someone stops it or it stops itself.
@@ -297,6 +382,7 @@
         super.setUp();
         mContext = getContext();
         mLocalService = new Intent(mContext, LocalService.class);
+        mLocalForegroundService = new Intent(mContext, LocalForegroundService.class);
         mLocalDeniedService = new Intent(mContext, LocalDeniedService.class);
         mLocalGrantedService = new Intent(mContext, LocalGrantedService.class);
         mLocalService_ApplicationHasPermission = new Intent(
@@ -327,6 +413,13 @@
                         finishBad("onStart() the first time on an object when it "
                                 + "should have been the second time");
                     }
+                } else if (mExpectedServiceState == STATE_START_3) {
+                    if (count == 3) {
+                        finishGood();
+                    } else {
+                        finishBad("onStart() the first time on an object when it "
+                                + "should have been the third time");
+                    }
                 } else {
                     finishBad("onStart() was called when not expected (state="
                             + mExpectedServiceState + ")");
@@ -371,6 +464,7 @@
     protected void tearDown() throws Exception {
         super.tearDown();
         mContext.stopService(mLocalService);
+        mContext.stopService(mLocalForegroundService);
         mContext.stopService(mLocalGrantedService);
         mContext.stopService(mLocalService_ApplicationHasPermission);
     }
@@ -388,6 +482,155 @@
         bindExpectResult(mLocalService);
     }
 
+    private void startForegroundService(int command) {
+        mContext.startService(new Intent(mLocalForegroundService).putExtras(LocalForegroundService
+                .newCommand(mStateReceiver, command)));
+    }
+
+    @MediumTest
+    public void testForegroundService_dontRemoveNotificationOnStop() throws Exception {
+        boolean success = false;
+        try {
+            // Start service as foreground - it should show notification #1
+            mExpectedServiceState = STATE_START_1;
+            startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+            waitForResultOrThrow(DELAY, "service to start first time");
+            assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+            // Stop foreground without removing notification - it should still show notification #1
+            mExpectedServiceState = STATE_START_2;
+            startForegroundService(
+                    LocalForegroundService.COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION);
+            waitForResultOrThrow(DELAY, "service to stop foreground");
+            assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+            // Sends another notification reusing the same notification id.
+            String newTitle = "YODA I AM";
+            sendNotififcation(1, newTitle);
+            assertNotification(1, newTitle);
+
+            // Start service as foreground again - it should kill notification #1 and show #2
+            mExpectedServiceState = STATE_START_3;
+            startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+            waitForResultOrThrow(DELAY, "service to start foreground 2nd time");
+            assertNoNotification(1);
+            assertNotification(2, LocalForegroundService.getNotificationTitle(2));
+
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.stopService(mLocalForegroundService);
+            }
+        }
+        mExpectedServiceState = STATE_DESTROY;
+        mContext.stopService(mLocalForegroundService);
+        waitForResultOrThrow(DELAY, "service to be destroyed");
+        assertNoNotification(1);
+        assertNoNotification(2);
+    }
+
+    @MediumTest
+    public void testForegroundService_removeNotificationOnStop() throws Exception {
+        testForegroundServiceRemoveNotificationOnStop(false);
+    }
+
+    @MediumTest
+    public void testForegroundService_removeNotificationOnStopUsingFlags() throws Exception {
+        testForegroundServiceRemoveNotificationOnStop(true);
+    }
+
+    private void testForegroundServiceRemoveNotificationOnStop(boolean usingFlags)
+            throws Exception {
+        boolean success = false;
+        try {
+            // Start service as foreground - it should show notification #1
+            mExpectedServiceState = STATE_START_1;
+            startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+            waitForResultOrThrow(DELAY, "service to start first time");
+            assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+            // Stop foreground removing notification
+            mExpectedServiceState = STATE_START_2;
+            if (usingFlags) {
+                startForegroundService(LocalForegroundService
+                        .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS);
+            } else {
+                startForegroundService(LocalForegroundService
+                        .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION);
+            }
+            waitForResultOrThrow(DELAY, "service to stop foreground");
+            assertNoNotification(1);
+
+            // Start service as foreground again - it should show notification #2
+            mExpectedServiceState = STATE_START_3;
+            startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+            waitForResultOrThrow(DELAY, "service to start as foreground 2nd time");
+            assertNotification(2, LocalForegroundService.getNotificationTitle(2));
+
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.stopService(mLocalForegroundService);
+            }
+        }
+        mExpectedServiceState = STATE_DESTROY;
+        mContext.stopService(mLocalForegroundService);
+        waitForResultOrThrow(DELAY, "service to be destroyed");
+        assertNoNotification(1);
+        assertNoNotification(2);
+    }
+
+    @MediumTest
+    public void testForegroundService_detachNotificationOnStop() throws Exception {
+        String newTitle = null;
+        boolean success = false;
+        try {
+
+            // Start service as foreground - it should show notification #1
+            mExpectedServiceState = STATE_START_1;
+            startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+            waitForResultOrThrow(DELAY, "service to start first time");
+            assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+            // Detaching notification
+            mExpectedServiceState = STATE_START_2;
+            startForegroundService(
+                    LocalForegroundService.COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION);
+            waitForResultOrThrow(DELAY, "service to stop foreground");
+            assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+            // Sends another notification reusing the same notification id.
+            newTitle = "YODA I AM";
+            sendNotififcation(1, newTitle);
+            assertNotification(1, newTitle);
+
+            // Start service as foreground again - it should show notification #2..
+            mExpectedServiceState = STATE_START_3;
+            startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+            waitForResultOrThrow(DELAY, "service to start as foreground 2nd time");
+            assertNotification(2, LocalForegroundService.getNotificationTitle(2));
+            //...but keeping notification #1
+            assertNotification(1, newTitle);
+
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.stopService(mLocalForegroundService);
+            }
+        }
+        mExpectedServiceState = STATE_DESTROY;
+        mContext.stopService(mLocalForegroundService);
+        waitForResultOrThrow(DELAY, "service to be destroyed");
+        if (newTitle == null) {
+            assertNoNotification(1);
+        } else {
+            assertNotification(1, newTitle);
+            cancelNotification(1);
+            assertNoNotification(1);
+        }
+        assertNoNotification(2);
+    }
+
     @MediumTest
     public void testLocalBindAction() throws Exception {
         bindExpectResult(new Intent(
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index a5aa2ac..8d0b084 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -779,6 +779,7 @@
                         "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported",
                         !supportZslNoiseReductionMode);
             }
+            counter++;
         }
     }
 
@@ -930,6 +931,7 @@
                         "All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed",
                         !hasFields);
             }
+            counter++;
         }
     }
 
@@ -1137,9 +1139,8 @@
                                 invalidSize.toString()),
                         config.isOutputSupportedFor(surf));
 
-                counter++;
             }
-
+            counter++;
         } // mCharacteristics
     }
 
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index d7ec5f1..c32be5c 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -35,6 +35,7 @@
 import static android.media.AudioManager.VIBRATE_TYPE_RINGER;
 import static android.provider.Settings.System.SOUND_EFFECTS_ENABLED;
 
+import android.app.NotificationManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.media.AudioManager;
@@ -52,6 +53,7 @@
     private final static long TIME_TO_PLAY = 2000;
     private final static String APPOPS_OP_STR = "android:write_settings";
     private AudioManager mAudioManager;
+    private NotificationManager mNm;
     private boolean mHasVibrator;
     private boolean mUseFixedVolume;
     private boolean mIsTelevision;
@@ -64,6 +66,7 @@
         Utils.enableAppOps(mContext.getPackageName(), APPOPS_OP_STR, getInstrumentation());
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+        mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mHasVibrator = (vibrator != null) && vibrator.hasVibrator();
         mUseFixedVolume = mContext.getResources().getBoolean(
                 Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
@@ -389,26 +392,28 @@
             }
             assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
 
-            // Apps without policy access cannot change vibrate -> silent.
-            Utils.toggleNotificationPolicyAccess(
-                    mContext.getPackageName(), getInstrumentation(), true);
-            mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
-            assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
-            Utils.toggleNotificationPolicyAccess(
-                    mContext.getPackageName(), getInstrumentation(), false);
+            if (mHasVibrator) {
+                // Apps without policy access cannot change vibrate -> silent.
+                Utils.toggleNotificationPolicyAccess(
+                        mContext.getPackageName(), getInstrumentation(), true);
+                mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+                assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+                Utils.toggleNotificationPolicyAccess(
+                        mContext.getPackageName(), getInstrumentation(), false);
 
-            try {
-                mAudioManager.setRingerMode(RINGER_MODE_SILENT);
-                fail("Apps without notification policy access cannot change ringer mode");
-            } catch (SecurityException e) {
+                try {
+                    mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+                    fail("Apps without notification policy access cannot change ringer mode");
+                } catch (SecurityException e) {
+                }
+
+                // Apps without policy access can change vibrate -> normal and vice versa.
+                assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+                mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+                assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+                mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+                assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
             }
-
-            // Apps without policy access can change vibrate -> normal and vice versa.
-            assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
-            mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
-            assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
-            mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
-            assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
         } finally {
             Utils.toggleNotificationPolicyAccess(
                     mContext.getPackageName(), getInstrumentation(), false);
@@ -618,18 +623,94 @@
         }
     }
 
-    public void testMute() throws Exception {
+    public void testMuteDndAffectedStreams() throws Exception {
         if (mUseFixedVolume) {
             return;
         }
+        int[] streams = { AudioManager.STREAM_RING };
+        try {
+            // Mute streams
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false);
+            // Verify streams cannot be unmuted without policy access.
+            for (int i = 0; i < streams.length; i++) {
+                try {
+                    mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
+                    assertEquals("Apps without Notification policy access can't change ringer mode",
+                            RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+                } catch (SecurityException e) {
+                }
 
+                try {
+                    mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE,
+                            0);
+                    assertEquals("Apps without Notification policy access can't change ringer mode",
+                            RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+                } catch (SecurityException e) {
+                }
+
+                try {
+                    mAudioManager.setStreamMute(streams[i], false);
+                    assertEquals("Apps without Notification policy access can't change ringer mode",
+                            RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+                } catch (SecurityException e) {
+                }
+            }
+
+            // This ensures we're out of vibrate or silent modes.
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+            for (int i = 0; i < streams.length; i++) {
+                // ensure each stream is on and turned up.
+                mAudioManager.setStreamVolume(streams[i],
+                        mAudioManager.getStreamMaxVolume(streams[i]),
+                        0);
+
+                Utils.toggleNotificationPolicyAccess(
+                        mContext.getPackageName(), getInstrumentation(), false);
+                try {
+                    mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+                    assertEquals("Apps without Notification policy access can't change ringer mode",
+                            RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+                } catch (SecurityException e) {
+                }
+                try {
+                    mAudioManager.adjustStreamVolume(
+                            streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+                    assertEquals("Apps without Notification policy access can't change ringer mode",
+                            RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+                } catch (SecurityException e) {
+                }
+
+                try {
+                    mAudioManager.setStreamMute(streams[i], true);
+                    assertEquals("Apps without Notification policy access can't change ringer mode",
+                            RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+                } catch (SecurityException e) {
+                }
+                Utils.toggleNotificationPolicyAccess(
+                        mContext.getPackageName(), getInstrumentation(), true);
+                testStreamMuting(streams[i]);
+            }
+        } finally {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false);
+        }
+    }
+
+    public void testMuteDndUnaffectedStreams() throws Exception {
+        if (mUseFixedVolume) {
+            return;
+        }
         int[] streams = {
                 AudioManager.STREAM_VOICE_CALL,
                 AudioManager.STREAM_MUSIC,
-                AudioManager.STREAM_RING,
-                AudioManager.STREAM_ALARM,
-                AudioManager.STREAM_NOTIFICATION,
-                AudioManager.STREAM_SYSTEM };
+                AudioManager.STREAM_ALARM
+        };
 
         try {
             int muteAffectedStreams = System.getInt(mContext.getContentResolver(),
@@ -664,34 +745,7 @@
                             mAudioManager.isStreamMute(streams[i]));
                     continue;
                 }
-                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
-                assertTrue("Muting stream " + streams[i] + " failed.",
-                        mAudioManager.isStreamMute(streams[i]));
-
-                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
-                assertFalse("Unmuting stream " + streams[i] + " failed.",
-                        mAudioManager.isStreamMute(streams[i]));
-
-                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
-                assertTrue("Toggling mute on stream " + streams[i] + " failed.",
-                        mAudioManager.isStreamMute(streams[i]));
-
-                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
-                assertFalse("Toggling mute on stream " + streams[i] + " failed.",
-                        mAudioManager.isStreamMute(streams[i]));
-
-                mAudioManager.setStreamMute(streams[i], true);
-                assertTrue("Muting stream " + streams[i] + " using setStreamMute failed",
-                        mAudioManager.isStreamMute(streams[i]));
-
-                // mute it three more times to verify the ref counting is gone.
-                mAudioManager.setStreamMute(streams[i], true);
-                mAudioManager.setStreamMute(streams[i], true);
-                mAudioManager.setStreamMute(streams[i], true);
-
-                mAudioManager.setStreamMute(streams[i], false);
-                assertFalse("Unmuting stream " + streams[i] + " using setStreamMute failed.",
-                        mAudioManager.isStreamMute(streams[i]));
+                testStreamMuting(streams[i]);
             }
         } finally {
             Utils.toggleNotificationPolicyAccess(
@@ -699,6 +753,37 @@
         }
     }
 
+    private void testStreamMuting(int stream) {
+        mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
+        assertTrue("Muting stream " + stream + " failed.",
+                mAudioManager.isStreamMute(stream));
+
+        mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, 0);
+        assertFalse("Unmuting stream " + stream + " failed.",
+                mAudioManager.isStreamMute(stream));
+
+        mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
+        assertTrue("Toggling mute on stream " + stream + " failed.",
+                mAudioManager.isStreamMute(stream));
+
+        mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
+        assertFalse("Toggling mute on stream " + stream + " failed.",
+                mAudioManager.isStreamMute(stream));
+
+        mAudioManager.setStreamMute(stream, true);
+        assertTrue("Muting stream " + stream + " using setStreamMute failed",
+                mAudioManager.isStreamMute(stream));
+
+        // mute it three more times to verify the ref counting is gone.
+        mAudioManager.setStreamMute(stream, true);
+        mAudioManager.setStreamMute(stream, true);
+        mAudioManager.setStreamMute(stream, true);
+
+        mAudioManager.setStreamMute(stream, false);
+        assertFalse("Unmuting stream " + stream + " using setStreamMute failed.",
+                mAudioManager.isStreamMute(stream));
+    }
+
     public void testSetInvalidRingerMode() {
         int ringerMode = mAudioManager.getRingerMode();
         mAudioManager.setRingerMode(-1337);
@@ -708,6 +793,110 @@
         assertEquals(ringerMode, mAudioManager.getRingerMode());
     }
 
+    public void testAdjustVolumeInTotalSilenceMode() throws Exception {
+        if (mUseFixedVolume || mIsTelevision) {
+            return;
+        }
+        try {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
+
+            int musicVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+            mAudioManager.adjustStreamVolume(
+                    AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
+            assertEquals(musicVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+        } finally {
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false);
+        }
+    }
+
+    public void testAdjustVolumeInAlarmsOnlyMode() throws Exception {
+        if (mUseFixedVolume || mIsTelevision) {
+            return;
+        }
+        try {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS);
+
+            int musicVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+            mAudioManager.adjustStreamVolume(
+                    AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
+            int volumeDelta =
+                    getVolumeDelta(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+            assertEquals(musicVolume + volumeDelta,
+                    mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+        } finally {
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false);
+        }
+    }
+
+    public void testSetStreamVolumeInTotalSilenceMode() throws Exception {
+        if (mUseFixedVolume || mIsTelevision) {
+            return;
+        }
+        try {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 1, 0);
+            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
+
+            int musicVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 7, 0);
+            assertEquals(musicVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+            mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 7, 0);
+            assertEquals(7, mAudioManager.getStreamVolume(AudioManager.STREAM_RING));
+        } finally {
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false);
+        }
+    }
+
+    public void testSetStreamVolumeInAlarmsOnlyMode() throws Exception {
+        if (mUseFixedVolume || mIsTelevision) {
+            return;
+        }
+        try {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 1, 0);
+            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS);
+
+            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 3, 0);
+            assertEquals(3, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+            mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 7, 0);
+            assertEquals(7, mAudioManager.getStreamVolume(AudioManager.STREAM_RING));
+        } finally {
+            setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false);
+        }
+    }
+
+    private void setInterruptionFilter(int filter) throws Exception {
+        mNm.setInterruptionFilter(filter);
+        for (int i = 0; i < 5; i++) {
+            if (mNm.getCurrentInterruptionFilter() == filter) {
+                break;
+            }
+            Thread.sleep(1000);
+        }
+    }
+
     private int getVolumeDelta(int volume) {
         return 1;
     }
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 4112466..231db97 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -38,9 +38,16 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.os.SystemProperties;
+import android.system.Os;
+import android.system.OsConstants;
 
 import com.android.internal.telephony.PhoneConstants;
 
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -57,7 +64,15 @@
 
     public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE;
     public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
+
     private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
+    private static final String TEST_HOST = "connectivitycheck.gstatic.com";
+    private static final int SOCKET_TIMEOUT_MS = 2000;
+    private static final int HTTP_PORT = 80;
+    private static final String HTTP_REQUEST =
+            "GET /generate_204 HTTP/1.0\r\n" +
+            "Host: " + TEST_HOST + "\r\n" +
+            "Connection: keep-alive\r\n\r\n";
 
     // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
     private static final String NETWORK_CALLBACK_ACTION =
@@ -249,6 +264,12 @@
         mCm.getBackgroundDataSetting();
     }
 
+    private NetworkRequest makeWifiNetworkRequest() {
+        return new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .build();
+    }
+
     /**
      * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
      * see if we get a callback for the TRANSPORT_WIFI transport type being available.
@@ -265,16 +286,14 @@
         }
 
         // We will register for a WIFI network being available or lost.
-        final NetworkRequest request = new NetworkRequest.Builder()
-                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                .build();
         final TestNetworkCallback callback = new TestNetworkCallback();
-        mCm.registerNetworkCallback(request, callback);
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
 
         final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
 
         final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
+        Network wifiNetwork = null;
 
         try {
             // Make sure WiFi is connected to an access point to start with.
@@ -285,10 +304,11 @@
             // Now we should expect to get a network callback about availability of the wifi
             // network even if it was already connected as a state-based action when the callback
             // is registered.
-            assertTrue("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
-                    callback.waitForAvailable());
+            wifiNetwork = callback.waitForAvailable();
+            assertNotNull("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
+                    wifiNetwork);
 
-            assertTrue("Did not receive NetworkCallback.onAvailable for any default network",
+            assertNotNull("Did not receive NetworkCallback.onAvailable for any default network",
                     defaultTrackingCallback.waitForAvailable());
         } catch (InterruptedException e) {
             fail("Broadcast receiver or NetworkCallback wait was interrupted.");
@@ -298,7 +318,7 @@
 
             // Return WiFi to its original enabled/disabled state.
             if (!previousWifiEnabledState) {
-                disconnectFromWifi();
+                disconnectFromWifi(wifiNetwork);
             }
         }
     }
@@ -329,10 +349,7 @@
                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
 
         // We will register for a WIFI network being available or lost.
-        NetworkRequest request = new NetworkRequest.Builder()
-                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                .build();
-        mCm.registerNetworkCallback(request, pendingIntent);
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
 
         final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
 
@@ -356,7 +373,7 @@
 
             // Return WiFi to its original enabled/disabled state.
             if (!previousWifiEnabledState) {
-                disconnectFromWifi();
+                disconnectFromWifi(null);
             }
         }
     }
@@ -370,8 +387,10 @@
 
         // We will toggle the state of wifi to generate a connectivity change.
         final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
+
         if (previousWifiEnabledState) {
-            disconnectFromWifi();
+            Network wifiNetwork = getWifiNetwork();
+            disconnectFromWifi(wifiNetwork);
         } else {
             connectToWifi();
         }
@@ -387,12 +406,16 @@
         if (previousWifiEnabledState) {
             connectToWifi();
         } else {
-            disconnectFromWifi();
+            disconnectFromWifi(null);
         }
     }
 
     /** Enable WiFi and wait for it to become connected to a network. */
-    private void connectToWifi() {
+    private Network connectToWifi() {
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+        Network wifiNetwork = null;
+
         ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
                 ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
         IntentFilter filter = new IntentFilter();
@@ -402,36 +425,94 @@
         boolean connected = false;
         try {
             assertTrue(mWifiManager.setWifiEnabled(true));
+            // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
+            wifiNetwork = callback.waitForAvailable();
+            assertNotNull(wifiNetwork);
             connected = receiver.waitForState();
         } catch (InterruptedException ex) {
             fail("connectToWifi was interrupted");
         } finally {
+            mCm.unregisterNetworkCallback(callback);
             mContext.unregisterReceiver(receiver);
         }
 
         assertTrue("Wifi must be configured to connect to an access point for this test.",
                 connected);
+        return wifiNetwork;
+    }
+
+    private Socket getBoundSocket(Network network, String host, int port) throws IOException {
+        InetSocketAddress addr = new InetSocketAddress(host, port);
+        Socket s = network.getSocketFactory().createSocket();
+        try {
+            s.setSoTimeout(SOCKET_TIMEOUT_MS);
+            s.connect(addr, SOCKET_TIMEOUT_MS);
+        } catch (IOException e) {
+            s.close();
+            throw e;
+        }
+        return s;
+    }
+
+    private void testHttpRequest(Socket s) throws IOException {
+        OutputStream out = s.getOutputStream();
+        InputStream in = s.getInputStream();
+
+        final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
+        byte[] responseBytes = new byte[4096];
+        out.write(requestBytes);
+        in.read(responseBytes);
+        assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
     }
 
     /** Disable WiFi and wait for it to become disconnected from the network. */
-    private void disconnectFromWifi() {
+    private void disconnectFromWifi(Network wifiNetworkToCheck) {
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+        Network lostWifiNetwork = null;
+
         ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
                 ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
         IntentFilter filter = new IntentFilter();
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mContext.registerReceiver(receiver, filter);
 
+        // Assert that we can establish a TCP connection on wifi.
+        Socket wifiBoundSocket = null;
+        if (wifiNetworkToCheck != null) {
+            try {
+                wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
+                testHttpRequest(wifiBoundSocket);
+            } catch (IOException e) {
+                fail("HTTP request before wifi disconnected failed with: " + e);
+            }
+        }
+
         boolean disconnected = false;
         try {
             assertTrue(mWifiManager.setWifiEnabled(false));
+            // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
+            lostWifiNetwork = callback.waitForLost();
+            assertNotNull(lostWifiNetwork);
             disconnected = receiver.waitForState();
         } catch (InterruptedException ex) {
             fail("disconnectFromWifi was interrupted");
         } finally {
+            mCm.unregisterNetworkCallback(callback);
             mContext.unregisterReceiver(receiver);
         }
 
         assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
+
+        // Check that the socket is closed when wifi disconnects.
+        if (wifiBoundSocket != null) {
+            try {
+                testHttpRequest(wifiBoundSocket);
+                fail("HTTP request should not succeed after wifi disconnects");
+            } catch (IOException expected) {
+                assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
+            }
+        }
     }
 
     /**
@@ -498,15 +579,48 @@
      */
     private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
         private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
+        private final CountDownLatch mLostLatch = new CountDownLatch(1);
 
-        public boolean waitForAvailable() throws InterruptedException {
-            return mAvailableLatch.await(30, TimeUnit.SECONDS);
+        public Network currentNetwork;
+        public Network lastLostNetwork;
+
+        public Network waitForAvailable() throws InterruptedException {
+            return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
+        }
+
+        public Network waitForLost() throws InterruptedException {
+            return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
         }
 
         @Override
         public void onAvailable(Network network) {
+            currentNetwork = network;
             mAvailableLatch.countDown();
         }
+
+        @Override
+        public void onLost(Network network) {
+            lastLostNetwork = network;
+            if (network.equals(currentNetwork)) {
+                currentNetwork = null;
+            }
+            mLostLatch.countDown();
+        }
+    }
+
+    private Network getWifiNetwork() {
+        TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+        Network network = null;
+        try {
+            network = callback.waitForAvailable();
+        } catch (InterruptedException e) {
+            fail("NetworkCallback wait was interrupted.");
+        } finally {
+            mCm.unregisterNetworkCallback(callback);
+        }
+        assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
+        return network;
     }
 
     /** Verify restricted networks cannot be requested. */
@@ -523,8 +637,6 @@
         try {
             mCm.requestNetwork(request, callback);
             fail("No exception thrown when restricted network requested.");
-        } catch (SecurityException e) {
-            // Expected.
-        }
+        } catch (SecurityException expected) {}
     }
 }
diff --git a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
index dbc8ede..be380c7 100644
--- a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
@@ -259,13 +259,14 @@
 #define FIXED_ADDR 0x45678000
 #define TIMEOUT 60 /* seconds */
 
-struct iovec *iovs = NULL;
-int fd[2];
+static struct iovec *iovs = NULL;
+static int fd[2];
+static void *overflow_addr;
 
 void* func_map(void*)
 {
-    munmap((void*)(FIXED_ADDR), PAGE_SIZE);
-    mmap((void*)(FIXED_ADDR), PAGE_SIZE, PROT_READ | PROT_WRITE,
+    munmap(overflow_addr, PAGE_SIZE);
+    overflow_addr = mmap(overflow_addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
             MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     return NULL;
 }
@@ -306,8 +307,10 @@
     iovs[OVERFLOW_BUF].iov_base = bufs[OVERFLOW_BUF];
     iovs[OVERFLOW_BUF].iov_len = IOV_LEN;
 
-    bufs[OVERFLOW_BUF] = mmap((void*)(FIXED_ADDR), PAGE_SIZE, PROT_READ | PROT_WRITE,
-            MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+    overflow_addr = mmap((void *) FIXED_ADDR, PAGE_SIZE, PROT_READ | PROT_WRITE,
+            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+    bufs[OVERFLOW_BUF] = overflow_addr;
     if (bufs[OVERFLOW_BUF] == MAP_FAILED) {
         ALOGE("mmap fixed addr failed:%s", strerror(errno));
         goto __close_pipe;
@@ -338,6 +341,12 @@
         pthread_join(thr_map, NULL);
         pthread_join(thr_readv, NULL);
 
+        bufs[OVERFLOW_BUF] = overflow_addr;
+        if (bufs[OVERFLOW_BUF] == MAP_FAILED) {
+            ALOGE("mmap fixed addr failed:%s", strerror(errno));
+            goto __free_bufs;
+        }
+
         clock_gettime(CLOCK_MONOTONIC, &ts);
         if ((ts.tv_sec - time) > TIMEOUT) {
             ret = true;
diff --git a/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java b/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
index bc916a7..bff6511 100644
--- a/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
@@ -83,6 +83,17 @@
         mGlVersion = 0;
     }
 
+    private static boolean mFixedSizeSet = false;
+    private static int mFixedWidth, mFixedHeight;
+    public static void setFixedSize(int width, int height) {
+        mFixedSizeSet = true;
+        mFixedWidth = width;
+        mFixedHeight = height;
+    }
+    public static void resetFixedSize() {
+        mFixedSizeSet = false;
+    }
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -101,6 +112,9 @@
         if (mRenderModeSet) {
             mView.setRenderMode(mRenderMode);
         }
+        if (mFixedSizeSet) {
+            mView.getHolder().setFixedSize(mFixedWidth, mFixedHeight);
+        }
         this.requestWindowFeature(Window.FEATURE_NO_TITLE);
         setContentView(mView);
     }
diff --git a/tests/tests/view/src/android/view/cts/MockView.java b/tests/tests/view/src/android/view/cts/MockView.java
index 3e140c2..f07e991 100644
--- a/tests/tests/view/src/android/view/cts/MockView.java
+++ b/tests/tests/view/src/android/view/cts/MockView.java
@@ -71,6 +71,10 @@
     private boolean mCalledOnKeyPreIme = false;
     private boolean mCalledGetPointerIcon = false;
     private boolean mCalledOnVisibilityAggregated = false;
+    private boolean mCalledDispatchStartTemporaryDetach = false;
+    private boolean mCalledDispatchFinishTemporaryDetach = false;
+    private boolean mCalledOnStartTemporaryDetach = false;
+    private boolean mCalledOnFinishTemporaryDetach = false;
 
     private int mOldWidth = -1;
     private int mOldHeight = -1;
@@ -634,6 +638,46 @@
         return mLastAggregatedVisibility;
     }
 
+    @Override
+    public void dispatchStartTemporaryDetach() {
+        super.dispatchStartTemporaryDetach();
+        mCalledDispatchStartTemporaryDetach = true;
+    }
+
+    @Override
+    public void dispatchFinishTemporaryDetach() {
+        super.dispatchFinishTemporaryDetach();
+        mCalledDispatchFinishTemporaryDetach = true;
+    }
+
+    @Override
+    public void onStartTemporaryDetach() {
+        super.onStartTemporaryDetach();
+        mCalledOnStartTemporaryDetach = true;
+    }
+
+    @Override
+    public void onFinishTemporaryDetach() {
+        super.onFinishTemporaryDetach();
+        mCalledOnFinishTemporaryDetach = true;
+    }
+
+    public boolean hasCalledDispatchStartTemporaryDetach() {
+        return mCalledDispatchStartTemporaryDetach;
+    }
+
+    public boolean hasCalledDispatchFinishTemporaryDetach() {
+        return mCalledDispatchFinishTemporaryDetach;
+    }
+
+    public boolean hasCalledOnStartTemporaryDetach() {
+        return mCalledOnStartTemporaryDetach;
+    }
+
+    public boolean hasCalledOnFinishTemporaryDetach() {
+        return mCalledOnFinishTemporaryDetach;
+    }
+
     public void reset() {
         mCalledOnCreateContextMenu = false;
 
@@ -674,6 +718,11 @@
         mCalledOnKeyPreIme = false;
         mCalledGetPointerIcon = false;
         mCalledOnVisibilityAggregated = false;
+        mCalledOnVisibilityAggregated = false;
+        mCalledDispatchStartTemporaryDetach = false;
+        mCalledDispatchFinishTemporaryDetach = false;
+        mCalledOnStartTemporaryDetach = false;
+        mCalledOnFinishTemporaryDetach = false;
 
         mOldWidth = -1;
         mOldHeight = -1;
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTests.java b/tests/tests/view/src/android/view/cts/PixelCopyTests.java
new file mode 100644
index 0000000..b54ecb9
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTests.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 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 android.view.cts;
+
+import android.app.Instrumentation;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.view.PixelCopy;
+import android.view.Surface;
+import android.view.SurfaceView;
+import android.view.PixelCopy.OnPixelCopyFinishedListener;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.GL_SCISSOR_TEST;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+import static android.opengl.GLES20.glEnable;
+import static android.opengl.GLES20.glScissor;
+
+import static org.junit.Assert.*;
+
+@MediumTest
+public class PixelCopyTests {
+    @Rule
+    public ActivityTestRule<GLSurfaceViewCtsActivity> mGLSurfaceViewActivityRule =
+            new ActivityTestRule<>(GLSurfaceViewCtsActivity.class, false, false);
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        assertNotNull(mInstrumentation);
+    }
+
+    @Test
+    public void testErrors() {
+        Bitmap dest = null;
+        SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
+        SurfaceTexture surfaceTexture = null;
+        Surface surface = null;
+
+        try {
+            surfaceTexture = new SurfaceTexture(false);
+            surface = new Surface(surfaceTexture);
+            try {
+                copyHelper.request(surface, dest);
+                fail("Should have generated an IllegalArgumentException, null dest!");
+            } catch (IllegalArgumentException iae) {
+                // success!
+            } catch (Throwable t) {
+                throw new AssertionError("Should have generated an IllegalArgumentException!", t);
+            }
+
+            dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+            int result = copyHelper.request(surface, dest);
+            assertEquals(PixelCopy.ERROR_SOURCE_NO_DATA, result);
+
+            dest.recycle();
+            try {
+                copyHelper.request(surface, dest);
+                fail("Should have generated an IllegalArgumentException!");
+            } catch (IllegalArgumentException iae) {
+                // success!
+            } catch (Throwable t) {
+                throw new AssertionError(
+                        "Should have generated an IllegalArgumentException, recycled bitmap!", t);
+            }
+        } finally {
+            try {
+                if (surface != null) surface.release();
+            } catch (Throwable t) {}
+            try {
+                if (surfaceTexture != null) surfaceTexture.release();
+            } catch (Throwable t) {}
+            surface = null;
+            surfaceTexture = null;
+        }
+    }
+
+    @Test
+    public void testGlProducer() {
+        try {
+            CountDownLatch swapFence = new CountDownLatch(2);
+            GLSurfaceViewCtsActivity.setGlVersion(2);
+            GLSurfaceViewCtsActivity.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+            GLSurfaceViewCtsActivity.setFixedSize(100, 100);
+            GLSurfaceViewCtsActivity.setRenderer(new QuadColorGLRenderer(
+                    Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, swapFence));
+
+            GLSurfaceViewCtsActivity activity =
+                    mGLSurfaceViewActivityRule.launchActivity(null);
+
+            while (!swapFence.await(5, TimeUnit.MILLISECONDS)) {
+                activity.getView().requestRender();
+            }
+
+            // Test a fullsize copy
+            Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+            SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
+            int result = copyHelper.request(activity.getView(), bitmap);
+            assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+            // Make sure nothing messed with the bitmap
+            assertEquals(100, bitmap.getWidth());
+            assertEquals(100, bitmap.getHeight());
+            assertEquals(Config.ARGB_8888, bitmap.getConfig());
+            assertBitmapQuadColor(bitmap,
+                    Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+
+            // Test that scaling works
+            // Since we only sample mid-pixel of each qudrant, filtering
+            // quality isn't tested
+            bitmap.reconfigure(20, 20, Config.ARGB_8888);
+            result = copyHelper.request(activity.getView(), bitmap);
+            assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+            // Make sure nothing messed with the bitmap
+            assertEquals(20, bitmap.getWidth());
+            assertEquals(20, bitmap.getHeight());
+            assertEquals(Config.ARGB_8888, bitmap.getConfig());
+            assertBitmapQuadColor(bitmap,
+                    Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+
+        } catch (InterruptedException e) {
+            fail("Interrupted, error=" + e.getMessage());
+        } finally {
+            GLSurfaceViewCtsActivity.resetFixedSize();
+            GLSurfaceViewCtsActivity.resetGlVersion();
+            GLSurfaceViewCtsActivity.resetRenderer();
+            GLSurfaceViewCtsActivity.resetRenderMode();
+        }
+    }
+
+    private static int getPixelFloatPos(Bitmap bitmap, float xpos, float ypos) {
+        return bitmap.getPixel((int) (bitmap.getWidth() * xpos), (int) (bitmap.getHeight() * ypos));
+    }
+
+    private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
+                int bottomLeft, int bottomRight) {
+        // Just quickly sample 4 pixels in the various regions.
+        assertEquals("Top left", topLeft, getPixelFloatPos(bitmap, .25f, .25f));
+        assertEquals("Top right", topRight, getPixelFloatPos(bitmap, .75f, .25f));
+        assertEquals("Bottom left", bottomLeft, getPixelFloatPos(bitmap, .25f, .75f));
+        assertEquals("Bottom right", bottomRight, getPixelFloatPos(bitmap, .75f, .75f));
+    }
+
+    private static class QuadColorGLRenderer implements Renderer {
+
+        private final int mTopLeftColor;
+        private final int mTopRightColor;
+        private final int mBottomLeftColor;
+        private final int mBottomRightColor;
+
+        private final CountDownLatch mFence;
+
+        private int mWidth, mHeight;
+
+        public QuadColorGLRenderer(int topLeft, int topRight,
+                int bottomLeft, int bottomRight, CountDownLatch fence) {
+            mTopLeftColor = topLeft;
+            mTopRightColor = topRight;
+            mBottomLeftColor = bottomLeft;
+            mBottomRightColor = bottomRight;
+            mFence = fence;
+        }
+
+        @Override
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        }
+
+        @Override
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            mWidth = width;
+            mHeight = height;
+        }
+
+        @Override
+        public void onDrawFrame(GL10 gl) {
+            int cx = mWidth / 2;
+            int cy = mHeight / 2;
+
+            glEnable(GL_SCISSOR_TEST);
+
+            glScissor(0, cy, cx, mHeight - cy);
+            clearColor(mTopLeftColor);
+
+            glScissor(cx, cy, mWidth - cx, mHeight - cy);
+            clearColor(mTopRightColor);
+
+            glScissor(0, 0, cx, cy);
+            clearColor(mBottomLeftColor);
+
+            glScissor(cx, 0, mWidth - cx, cy);
+            clearColor(mBottomRightColor);
+
+            mFence.countDown();
+        }
+
+        private void clearColor(int color) {
+            glClearColor(Color.red(color) / 255.0f,
+                    Color.green(color) / 255.0f,
+                    Color.blue(color) / 255.0f,
+                    Color.alpha(color) / 255.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
+        }
+    }
+
+    private static class SynchronousPixelCopy implements OnPixelCopyFinishedListener {
+        private static Handler sHandler;
+        static {
+            HandlerThread thread = new HandlerThread("PixelCopyHelper");
+            thread.start();
+            sHandler = new Handler(thread.getLooper());
+        }
+
+        private int mStatus = -1;
+
+        public int request(Surface source, Bitmap dest) {
+            synchronized (this) {
+                PixelCopy.request(source, dest, this, sHandler);
+                return getResultLocked();
+            }
+        }
+
+        public int request(SurfaceView source, Bitmap dest) {
+            synchronized (this) {
+                PixelCopy.request(source, dest, this, sHandler);
+                return getResultLocked();
+            }
+        }
+
+        private int getResultLocked() {
+            try {
+                this.wait(1000);
+            } catch (InterruptedException e) {
+                fail("PixelCopy request didn't complete within 1s");
+            }
+            return mStatus;
+        }
+
+        @Override
+        public void onPixelCopyFinished(int copyResult) {
+            synchronized (this) {
+                mStatus = copyResult;
+                this.notify();
+            }
+        }
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 49979ca..dba02ee 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -1769,6 +1769,164 @@
         assertTrue(vgParent.isStartActionModeForChildTypedCalled);
     }
 
+    public void testTemporaryDetach() {
+        // [vgParent]
+        //   - [viewParent1]
+        //   - [viewParent1]
+        //   - [vg]
+        //     - [view1]
+        //     - [view2]
+        MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
+        TemporaryDetachingMockView viewParent1 = new TemporaryDetachingMockView(mContext);
+        TemporaryDetachingMockView viewParent2 = new TemporaryDetachingMockView(mContext);
+        vgParent.addView(viewParent1);
+        vgParent.addView(viewParent2);
+        MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
+        vgParent.addView(vg);
+        TemporaryDetachingMockView view1 = new TemporaryDetachingMockView(mContext);
+        TemporaryDetachingMockView view2 = new TemporaryDetachingMockView(mContext);
+        vg.addView(view1);
+        vg.addView(view2);
+
+        // Make sure that no View is temporarity detached in the initial state.
+        assertFalse(viewParent1.isTemporarilyDetached());
+        assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, viewParent1.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
+        assertFalse(viewParent2.isTemporarilyDetached());
+        assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, viewParent2.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
+        assertFalse(view1.isTemporarilyDetached());
+        assertEquals(0, view1.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, view1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, view1.getOnStartTemporaryDetachCount());
+        assertEquals(0, view1.getOnFinishTemporaryDetachCount());
+        assertFalse(view2.isTemporarilyDetached());
+        assertEquals(0, view2.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, view2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, view2.getOnStartTemporaryDetachCount());
+        assertEquals(0, view2.getOnFinishTemporaryDetachCount());
+
+        // [vgParent]
+        //   - [viewParent1]
+        //   - [viewParent1]
+        //   - [vg]           <- dispatchStartTemporaryDetach()
+        //     - [view1]
+        //     - [view2]
+        vg.dispatchStartTemporaryDetach();
+
+        assertFalse(viewParent1.isTemporarilyDetached());
+        assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, viewParent1.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
+        assertFalse(viewParent2.isTemporarilyDetached());
+        assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, viewParent2.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
+        assertTrue(view1.isTemporarilyDetached());
+        assertEquals(1, view1.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, view1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, view1.getOnStartTemporaryDetachCount());
+        assertEquals(0, view1.getOnFinishTemporaryDetachCount());
+        assertTrue(view2.isTemporarilyDetached());
+        assertEquals(1, view2.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, view2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, view2.getOnStartTemporaryDetachCount());
+        assertEquals(0, view2.getOnFinishTemporaryDetachCount());
+
+        // [vgParent]
+        //   - [viewParent1]
+        //   - [viewParent1]
+        //   - [vg]           <- dispatchFinishTemporaryDetach()
+        //     - [view1]
+        //     - [view2]
+        vg.dispatchFinishTemporaryDetach();
+
+        assertFalse(viewParent1.isTemporarilyDetached());
+        assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, viewParent1.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
+        assertFalse(viewParent2.isTemporarilyDetached());
+        assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(0, viewParent2.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
+        assertFalse(view1.isTemporarilyDetached());
+        assertEquals(1, view1.getDispatchStartTemporaryDetachCount());
+        assertEquals(1, view1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, view1.getOnStartTemporaryDetachCount());
+        assertEquals(1, view1.getOnFinishTemporaryDetachCount());
+        assertFalse(view2.isTemporarilyDetached());
+        assertEquals(1, view2.getDispatchStartTemporaryDetachCount());
+        assertEquals(1, view2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, view2.getOnStartTemporaryDetachCount());
+        assertEquals(1, view2.getOnFinishTemporaryDetachCount());
+
+        // [vgParent]         <- dispatchStartTemporaryDetach()
+        //   - [viewParent1]
+        //   - [viewParent1]
+        //   - [vg]
+        //     - [view1]
+        //     - [view2]
+        vgParent.dispatchStartTemporaryDetach();
+
+        assertTrue(viewParent1.isTemporarilyDetached());
+        assertEquals(1, viewParent1.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, viewParent1.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
+        assertTrue(viewParent2.isTemporarilyDetached());
+        assertEquals(1, viewParent2.getDispatchStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, viewParent2.getOnStartTemporaryDetachCount());
+        assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
+        assertTrue(view1.isTemporarilyDetached());
+        assertEquals(2, view1.getDispatchStartTemporaryDetachCount());
+        assertEquals(1, view1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(2, view1.getOnStartTemporaryDetachCount());
+        assertEquals(1, view1.getOnFinishTemporaryDetachCount());
+        assertTrue(view2.isTemporarilyDetached());
+        assertEquals(2, view2.getDispatchStartTemporaryDetachCount());
+        assertEquals(1, view2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(2, view2.getOnStartTemporaryDetachCount());
+        assertEquals(1, view2.getOnFinishTemporaryDetachCount());
+
+        // [vgParent]         <- dispatchFinishTemporaryDetach()
+        //   - [viewParent1]
+        //   - [viewParent1]
+        //   - [vg]
+        //     - [view1]
+        //     - [view2]
+        vgParent.dispatchFinishTemporaryDetach();
+
+        assertFalse(viewParent1.isTemporarilyDetached());
+        assertEquals(1, viewParent1.getDispatchStartTemporaryDetachCount());
+        assertEquals(1, viewParent1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, viewParent1.getOnStartTemporaryDetachCount());
+        assertEquals(1, viewParent1.getOnFinishTemporaryDetachCount());
+        assertFalse(viewParent2.isTemporarilyDetached());
+        assertEquals(1, viewParent2.getDispatchStartTemporaryDetachCount());
+        assertEquals(1, viewParent2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(1, viewParent2.getOnStartTemporaryDetachCount());
+        assertEquals(1, viewParent2.getOnFinishTemporaryDetachCount());
+        assertFalse(view1.isTemporarilyDetached());
+        assertEquals(2, view1.getDispatchStartTemporaryDetachCount());
+        assertEquals(2, view1.getDispatchFinishTemporaryDetachCount());
+        assertEquals(2, view1.getOnStartTemporaryDetachCount());
+        assertEquals(2, view1.getOnFinishTemporaryDetachCount());
+        assertFalse(view2.isTemporarilyDetached());
+        assertEquals(2, view2.getDispatchStartTemporaryDetachCount());
+        assertEquals(2, view2.getDispatchFinishTemporaryDetachCount());
+        assertEquals(2, view2.getOnStartTemporaryDetachCount());
+        assertEquals(2, view2.getOnFinishTemporaryDetachCount());
+    }
+
     private static final ActionMode.Callback NO_OP_ACTION_MODE_CALLBACK =
             new ActionMode.Callback() {
                 @Override
@@ -2422,6 +2580,57 @@
         }
     }
 
+    static final class TemporaryDetachingMockView extends View {
+        private int mDispatchStartTemporaryDetachCount = 0;
+        private int mDispatchFinishTemporaryDetachCount = 0;
+        private int mOnStartTemporaryDetachCount = 0;
+        private int mOnFinishTemporaryDetachCount = 0;
+
+        public TemporaryDetachingMockView(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void dispatchStartTemporaryDetach() {
+            super.dispatchStartTemporaryDetach();
+            mDispatchStartTemporaryDetachCount += 1;
+        }
+
+        @Override
+        public void dispatchFinishTemporaryDetach() {
+            super.dispatchFinishTemporaryDetach();
+            mDispatchFinishTemporaryDetachCount += 1;
+        }
+
+        @Override
+        public void onStartTemporaryDetach() {
+            super.onStartTemporaryDetach();
+            mOnStartTemporaryDetachCount += 1;
+        }
+
+        @Override
+        public void onFinishTemporaryDetach() {
+            super.onFinishTemporaryDetach();
+            mOnFinishTemporaryDetachCount += 1;
+        }
+
+        public int getDispatchStartTemporaryDetachCount() {
+            return mDispatchStartTemporaryDetachCount;
+        }
+
+        public int getDispatchFinishTemporaryDetachCount() {
+            return mDispatchFinishTemporaryDetachCount;
+        }
+
+        public int getOnStartTemporaryDetachCount() {
+            return mOnStartTemporaryDetachCount;
+        }
+
+        public int getOnFinishTemporaryDetachCount() {
+            return mOnFinishTemporaryDetachCount;
+        }
+    }
+
     @Override
     public void setResult(int resultCode) {
         synchronized (mSync) {
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 426a20f..6a431a2 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -83,7 +83,6 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.LinearLayout;
@@ -3561,107 +3560,41 @@
     }
 
     public void testOnStartAndFinishTemporaryDetach() throws Throwable {
-        final MockListView listView = new MockListView(mActivity);
-        List<String> items = new ArrayList<>();
-        items.add("1");
-        items.add("2");
-        items.add("3");
-        final Adapter<String> adapter = new Adapter<>(mActivity, 0, items);
+        final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
+
+        assertFalse(view.isTemporarilyDetached());
+        assertFalse(view.hasCalledDispatchStartTemporaryDetach());
+        assertFalse(view.hasCalledDispatchFinishTemporaryDetach());
+        assertFalse(view.hasCalledOnStartTemporaryDetach());
+        assertFalse(view.hasCalledOnFinishTemporaryDetach());
 
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mActivity.setContentView(listView);
-                listView.setAdapter(adapter);
+                view.dispatchStartTemporaryDetach();
             }
         });
         getInstrumentation().waitForIdleSync();
-        final MockView focusChild = (MockView) listView.getChildAt(0);
+
+        assertTrue(view.isTemporarilyDetached());
+        assertTrue(view.hasCalledDispatchStartTemporaryDetach());
+        assertFalse(view.hasCalledDispatchFinishTemporaryDetach());
+        assertTrue(view.hasCalledOnStartTemporaryDetach());
+        assertFalse(view.hasCalledOnFinishTemporaryDetach());
 
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                focusChild.requestFocus();
+                view.dispatchFinishTemporaryDetach();
             }
         });
         getInstrumentation().waitForIdleSync();
-        assertTrue(listView.getChildAt(0).isFocused());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                listView.detachViewFromParent(focusChild);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertFalse(listView.hasCalledOnStartTemporaryDetach());
-        assertFalse(listView.hasCalledOnFinishTemporaryDetach());
-    }
-
-    private static class MockListView extends ListView {
-        private boolean mCalledOnStartTemporaryDetach = false;
-        private boolean mCalledOnFinishTemporaryDetach = false;
-
-        public MockListView(Context context) {
-            super(context);
-        }
-
-        @Override
-        protected void detachViewFromParent(View child) {
-            super.detachViewFromParent(child);
-        }
-
-        @Override
-        public void onFinishTemporaryDetach() {
-            super.onFinishTemporaryDetach();
-            mCalledOnFinishTemporaryDetach = true;
-        }
-
-        public boolean hasCalledOnFinishTemporaryDetach() {
-            return mCalledOnFinishTemporaryDetach;
-        }
-
-        @Override
-        public void onStartTemporaryDetach() {
-            super.onStartTemporaryDetach();
-            mCalledOnStartTemporaryDetach = true;
-        }
-
-        public boolean hasCalledOnStartTemporaryDetach() {
-            return mCalledOnStartTemporaryDetach;
-        }
-
-        public void reset() {
-            mCalledOnStartTemporaryDetach = false;
-            mCalledOnFinishTemporaryDetach = false;
-        }
-    }
-
-    private static class Adapter<T> extends ArrayAdapter<T> {
-        ArrayList<MockView> views = new ArrayList<>();
-
-        public Adapter(Context context, int textViewResourceId, List<T> objects) {
-            super(context, textViewResourceId, objects);
-            for (int i = 0; i < objects.size(); i++) {
-                views.add(new MockView(context));
-                views.get(i).setFocusable(true);
-            }
-        }
-
-        @Override
-        public int getCount() {
-            return views.size();
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            return views.get(position);
-        }
+        assertFalse(view.isTemporarilyDetached());
+        assertTrue(view.hasCalledDispatchStartTemporaryDetach());
+        assertTrue(view.hasCalledDispatchFinishTemporaryDetach());
+        assertTrue(view.hasCalledOnStartTemporaryDetach());
+        assertTrue(view.hasCalledOnFinishTemporaryDetach());
     }
 
     public void testKeyPreIme() throws Throwable {
diff --git a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
index 1394ccd..b6dc991 100644
--- a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
@@ -64,6 +64,7 @@
     // url, and different domains.
     private static final String URL_1 = "https://www.example.com";
     private static final String URL_2 = "https://www.example.org";
+    private static final String URL_INSECURE = "http://www.example.org";
 
     private static final String JS_INTERFACE_NAME = "Android";
     private static final int POLLING_TIMEOUT = 60 * 1000;
@@ -536,7 +537,7 @@
         originCheck.run();
     }
 
-    // Test loading pages and checks rejecting once and recjecting the domain forever
+    // Test loading pages and checks rejecting once and rejecting the domain forever
     public void testSimpleGeolocationRequestReject() throws Exception {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
@@ -591,6 +592,26 @@
         falseCheck.run();
     }
 
+    // Test deny geolocation on insecure origins
+    public void testGeolocationRequestDeniedOnInsecureOrigin() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        final TestSimpleGeolocationRequestWebChromeClient chromeClientAcceptAlways =
+                new TestSimpleGeolocationRequestWebChromeClient(mOnUiThread, true, true);
+        mOnUiThread.setWebChromeClient(chromeClientAcceptAlways);
+        loadUrlAndUpdateLocation(URL_INSECURE);
+        Callable<Boolean> locationDenied = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return mJavascriptStatusReceiver.mDenied;
+            }
+        };
+        PollingCheck.check("JS got position", POLLING_TIMEOUT, locationDenied);
+        // The geolocation permission prompt should not be called
+        assertFalse(chromeClientAcceptAlways.mReceivedRequest);
+    }
+
     // Object added to the page via AddJavascriptInterface() that is used by the test Javascript to
     // notify back to Java when a location or error is received.
     public final static class JavascriptStatusReceiver {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 3f4fd92..6d67547 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -203,6 +203,46 @@
     }
 
     @UiThreadTest
+    public void testCreatingWebViewWithDeviceEncrpytionFails() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        Context deviceEncryptedContext = getActivity().createDeviceProtectedStorageContext();
+        try {
+            new WebView(deviceEncryptedContext);
+        } catch (IllegalArgumentException e) {
+            return;
+        }
+
+        Assert.fail("WebView should have thrown exception when creating with a device " +
+                "protected storage context");
+    }
+
+    @UiThreadTest
+    public void testCreatingWebViewWithMultipleEncryptionContext() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        // Credential encrpytion is the default. Create one here for the sake of clarity.
+        Context credentialEncryptedContext = getActivity().createCredentialProtectedStorageContext();
+        Context deviceEncryptedContext = getActivity().createDeviceProtectedStorageContext();
+
+        // No exception should be thrown with credential encryption context.
+        new WebView(credentialEncryptedContext);
+
+        try {
+            new WebView(deviceEncryptedContext);
+        } catch (IllegalArgumentException e) {
+            return;
+        }
+
+        Assert.fail("WebView should have thrown exception when creating with a device " +
+                "protected storage context");
+    }
+
+    @UiThreadTest
     public void testCreatingWebViewCreatesCookieSyncManager() throws Exception {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 48f2f06..224966d 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -254,7 +254,9 @@
         </activity>
 
         <activity android:name="android.widget.cts.TextViewCtsActivity"
-            android:label="TextViewCtsActivity">
+            android:label="TextViewCtsActivity"
+            android:screenOrientation="nosensor"
+            android:windowSoftInputMode="stateAlwaysHidden">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -286,7 +288,7 @@
         </activity>
 
         <activity android:name="android.widget.cts.VideoViewCtsActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize">
+            android:configChanges="keyboardHidden|orientation|screenSize"
             android:label="VideoViewCtsActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -295,7 +297,9 @@
         </activity>
 
         <activity android:name="android.widget.cts.AutoCompleteCtsActivity"
-            android:label="AutoCompleteCtsActivity">
+            android:label="AutoCompleteCtsActivity"
+            android:screenOrientation="nosensor"
+            android:windowSoftInputMode="stateAlwaysHidden">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
diff --git a/tests/tests/widget/res/layout/autocompletetextview_layout.xml b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
index 25a8541..27eccab 100644
--- a/tests/tests/widget/res/layout/autocompletetextview_layout.xml
+++ b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
@@ -24,7 +24,7 @@
         android:layout_height="wrap_content"
         android:text="@string/notify" />
 
-    <AutoCompleteTextView android:id="@+id/autocompletetv_edit"
+    <android.widget.cts.AutoCompleteTextViewNoIme android:id="@+id/autocompletetv_edit"
         android:completionThreshold="1"
         android:completionHint="@string/tabs_1"
         android:layout_width="match_parent"
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewNoIme.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewNoIme.java
new file mode 100644
index 0000000..c4ada69
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewNoIme.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 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 android.widget.cts;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.AutoCompleteTextView;
+
+/**
+ * An AutoCompleteTextView that returns null for onCreateInputConnection.
+ */
+public class AutoCompleteTextViewNoIme extends AutoCompleteTextView {
+
+    public AutoCompleteTextViewNoIme(Context context) {
+        super(context);
+    }
+
+    public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes, Resources.Theme popupTheme) {
+        super(context, attrs, defStyleAttr, defStyleRes, popupTheme);
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        return null;
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index ea0861f..073a90b 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -475,6 +475,8 @@
         promptView.getLocationOnScreen(promptViewOnScreenXY);
 
         final ListView listView = mPopupWindow.getListView();
+        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+
         final View firstListChild = listView.getChildAt(0);
         final int[] firstChildOnScreenXY = new int[2];
         firstListChild.getLocationOnScreen(firstChildOnScreenXY);
@@ -498,6 +500,8 @@
         promptView.getLocationOnScreen(promptViewOnScreenXY);
 
         final ListView listView = mPopupWindow.getListView();
+        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+
         final View lastListChild = listView.getChildAt(listView.getChildCount() - 1);
         final int[] lastChildOnScreenXY = new int[2];
         lastListChild.getLocationOnScreen(lastChildOnScreenXY);
@@ -595,6 +599,8 @@
                 .withDismissListener().withItemSelectedListener();
         mPopupWindowBuilder.show();
 
+        final View root = mPopupWindow.getListView().getRootView();
+
         // "Point" our custom extension of EditText to our ListPopupWindow
         final MockViewForListPopupWindow anchor =
                 (MockViewForListPopupWindow) mPopupWindow.getAnchorView();
@@ -617,6 +623,8 @@
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
         mInstrumentation.waitForIdleSync();
 
+        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+
         // At this point we expect that item #2 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
                 any(AdapterView.class), any(View.class), eq(2), eq(2L));
@@ -627,6 +635,8 @@
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
         mInstrumentation.waitForIdleSync();
 
+        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+
         // At this point we expect that item #1 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(2)).onItemSelected(
                 any(AdapterView.class), any(View.class), eq(1), eq(1L));
@@ -637,6 +647,8 @@
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
         mInstrumentation.waitForIdleSync();
 
+        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+
         // At this point we expect that item #0 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
                 any(AdapterView.class), any(View.class), eq(0), eq(0L));
diff --git a/tests/tests/widget/src/android/widget/cts/ListViewTest.java b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
index 3ee9ead..b5a92e9 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
@@ -37,7 +37,6 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnDrawListener;
 import android.view.animation.LayoutAnimationController;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
@@ -569,7 +568,7 @@
      * The following functions are merged from frameworktest.
      */
     @MediumTest
-    public void testRequestLayout() throws Exception {
+    public void testRequestLayoutCallsMeasure() throws Exception {
         ListView listView = new ListView(mActivity);
         List<String> items = new ArrayList<>();
         items.add("hello");
@@ -643,6 +642,114 @@
         }
     }
 
+    @MediumTest
+    public void testRequestLayoutWithTemporaryDetach() throws Exception {
+        ListView listView = new ListView(mActivity);
+        List<String> items = new ArrayList<>();
+        items.add("0");
+        items.add("1");
+        items.add("2");
+        final TemporarilyDetachableMockViewAdapter<String> adapter =
+                new TemporarilyDetachableMockViewAdapter<>(
+                        mActivity, android.R.layout.simple_list_item_1, items);
+        mInstrumentation.runOnMainSync(() -> {
+            listView.setAdapter(adapter);
+            mActivity.setContentView(listView);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(items.size(), listView.getCount());
+        final TemporarilyDetachableMockView childView0 =
+                (TemporarilyDetachableMockView) listView.getChildAt(0);
+        final TemporarilyDetachableMockView childView1 =
+                (TemporarilyDetachableMockView) listView.getChildAt(1);
+        final TemporarilyDetachableMockView childView2 =
+                (TemporarilyDetachableMockView) listView.getChildAt(2);
+        assertNotNull(childView0);
+        assertNotNull(childView1);
+        assertNotNull(childView2);
+
+        // Make sure that the childView1 has focus.
+        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, childView1, childView1::requestFocus);
+        assertTrue(childView1.isFocused());
+
+        // Make sure that ListView#requestLayout() is optimized when nothing is changed.
+        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, listView::requestLayout);
+        assertEquals(childView0, listView.getChildAt(0));
+        assertEquals(childView1, listView.getChildAt(1));
+        assertEquals(childView2, listView.getChildAt(2));
+    }
+
+    private class TemporarilyDetachableMockView extends View {
+
+        private boolean mIsDispatchingStartTemporaryDetach = false;
+        private boolean mIsDispatchingFinishTemporaryDetach = false;
+
+        public TemporarilyDetachableMockView(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void dispatchStartTemporaryDetach() {
+            mIsDispatchingStartTemporaryDetach = true;
+            super.dispatchStartTemporaryDetach();
+            mIsDispatchingStartTemporaryDetach = false;
+        }
+
+        @Override
+        public void dispatchFinishTemporaryDetach() {
+            mIsDispatchingFinishTemporaryDetach = true;
+            super.dispatchFinishTemporaryDetach();
+            mIsDispatchingFinishTemporaryDetach = false;
+        }
+
+        @Override
+        public void onStartTemporaryDetach() {
+            super.onStartTemporaryDetach();
+            if (!mIsDispatchingStartTemporaryDetach) {
+                throw new IllegalStateException("#onStartTemporaryDetach() must be indirectly"
+                        + " called via #dispatchStartTemporaryDetach()");
+            }
+        }
+
+        @Override
+        public void onFinishTemporaryDetach() {
+            super.onFinishTemporaryDetach();
+            if (!mIsDispatchingFinishTemporaryDetach) {
+                throw new IllegalStateException("#onStartTemporaryDetach() must be indirectly"
+                        + " called via #dispatchFinishTemporaryDetach()");
+            }
+        }
+    }
+
+    private class TemporarilyDetachableMockViewAdapter<T> extends ArrayAdapter<T> {
+        ArrayList<TemporarilyDetachableMockView> views = new ArrayList<>();
+
+        public TemporarilyDetachableMockViewAdapter(Context context, int textViewResourceId,
+                List<T> objects) {
+            super(context, textViewResourceId, objects);
+            for (int i = 0; i < objects.size(); i++) {
+                views.add(new TemporarilyDetachableMockView(context));
+                views.get(i).setFocusable(true);
+            }
+        }
+
+        @Override
+        public int getCount() {
+            return views.size();
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            return views.get(position);
+        }
+    }
+
     public void testTransientStateUnstableIds() throws Exception {
         final ListView listView = mListView;
         final ArrayList<String> items = new ArrayList<String>(Arrays.asList(mCountryList));
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 40d42a2..effc685 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -23,6 +23,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
 import android.content.res.Resources.NotFoundException;
+import android.cts.util.KeyEventUtil;
 import android.cts.util.PollingCheck;
 import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
@@ -123,6 +124,7 @@
             + "this text, I would love to see the kind of devices you guys now use!";
     private static final long TIMEOUT = 5000;
     private CharSequence mTransformedText;
+    private KeyEventUtil mKeyEventUtil;
 
     public TextViewTest() {
         super("android.widget.cts", TextViewCtsActivity.class);
@@ -139,6 +141,7 @@
             }
         }.run();
         mInstrumentation = getInstrumentation();
+        mKeyEventUtil = new KeyEventUtil(mInstrumentation);
     }
 
     /**
@@ -1400,7 +1403,7 @@
         initTextViewForTyping();
 
         // Type some text.
-        mInstrumentation.sendStringSync("abc");
+        mKeyEventUtil.sendString(mTextView, "abc");
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Precondition: The cursor is at the end of the text.
@@ -1432,8 +1435,9 @@
         initTextViewForTyping();
 
         // Simulate deleting text and undoing it.
-        mInstrumentation.sendStringSync("xyz");
-        sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+        mKeyEventUtil.sendString(mTextView, "xyz");
+        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL,
+                KeyEvent.KEYCODE_DEL);
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Precondition: The text was actually deleted.
@@ -1563,8 +1567,9 @@
         initTextViewForTyping();
 
         // Create two undo operations, an insert and a delete.
-        mInstrumentation.sendStringSync("xyz");
-        sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+        mKeyEventUtil.sendString(mTextView, "xyz");
+        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL,
+                KeyEvent.KEYCODE_DEL);
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Calling setText() clears both undo operations, so undo doesn't happen.
@@ -1585,7 +1590,7 @@
         initTextViewForTyping();
 
         // Type some text. This creates an undo entry.
-        mInstrumentation.sendStringSync("abc");
+        mKeyEventUtil.sendString(mTextView, "abc");
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Undo the typing to create a redo entry.
@@ -1604,7 +1609,7 @@
         initTextViewForTyping();
 
         // Type some text.
-        mInstrumentation.sendStringSync("abc");
+        mKeyEventUtil.sendString(mTextView, "abc");
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Programmatically append some text.
@@ -1627,7 +1632,7 @@
         initTextViewForTyping();
 
         // Type some text.
-        mInstrumentation.sendStringSync("abc");
+        mKeyEventUtil.sendString(mTextView, "abc");
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Directly modify the underlying Editable to insert some text.
@@ -1676,7 +1681,7 @@
         mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
 
         // Type some text.
-        mInstrumentation.sendStringSync("abc");
+        mKeyEventUtil.sendString(mTextView, "abc");
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // TextWatcher altered the text.
@@ -1714,7 +1719,7 @@
         initTextViewForTyping();
 
         // Type some text.
-        mInstrumentation.sendStringSync("abc");
+        mKeyEventUtil.sendString(mTextView, "abc");
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Pressing Control-Z triggers undo.
@@ -1737,7 +1742,7 @@
         initTextViewForTyping();
 
         // Type some text to create an undo operation.
-        mInstrumentation.sendStringSync("abc");
+        mKeyEventUtil.sendString(mTextView, "abc");
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Parcel and unparcel the TextView.
@@ -1748,7 +1753,7 @@
         mInstrumentation.waitForIdleSync();
 
         // Delete a character to create a new undo operation.
-        sendKeys(KeyEvent.KEYCODE_DEL);
+        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 assertEquals("ab", mTextView.getText().toString());
@@ -1775,8 +1780,8 @@
         initTextViewForTyping();
 
         // Type and delete to create two new undo operations.
-        mInstrumentation.sendStringSync("a");
-        sendKeys(KeyEvent.KEYCODE_DEL);
+        mKeyEventUtil.sendString(mTextView, "a");
+        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Empty the undo stack then parcel and unparcel the TextView. While the undo
@@ -1790,8 +1795,8 @@
         mInstrumentation.waitForIdleSync();
 
         // Create two more undo operations.
-        mInstrumentation.sendStringSync("b");
-        sendKeys(KeyEvent.KEYCODE_DEL);
+        mKeyEventUtil.sendString(mTextView, "b");
+        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 // Verify undo still works.
diff --git a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
index 02ac28c..e9ef867 100644
--- a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
@@ -19,6 +19,8 @@
 import junit.framework.Assert;
 
 import android.app.Instrumentation;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnDrawListener;
@@ -37,10 +39,11 @@
      *
      * @param instrumentation the instrumentation used to run the test
      * @param view the view whose tree should be drawn before returning
-     * @param runner the runnable to run on the main thread
+     * @param runner the runnable to run on the main thread, or {@code null} to
+     *               simply force invalidation and a draw pass
      */
-    public static void runOnMainAndDrawSync(Instrumentation instrumentation,
-            final View view, final Runnable runner) {
+    public static void runOnMainAndDrawSync(@NonNull Instrumentation instrumentation,
+            @NonNull final View view, @Nullable final Runnable runner) {
         final CountDownLatch latch = new CountDownLatch(1);
 
         instrumentation.runOnMainSync(() -> {
@@ -54,7 +57,12 @@
             };
 
             observer.addOnDrawListener(listener);
-            runner.run();
+
+            if (runner != null) {
+                runner.run();
+            } else {
+                view.invalidate();
+            }
         });
 
         try {