Merge "media.Vp8EncoderTest: comment out asynchronous testing"
diff --git a/apps/CtsVerifier/res/layout/snsr_hrm.xml b/apps/CtsVerifier/res/layout/snsr_hrm.xml
index 612b424..506ba9f 100644
--- a/apps/CtsVerifier/res/layout/snsr_hrm.xml
+++ b/apps/CtsVerifier/res/layout/snsr_hrm.xml
@@ -27,6 +27,21 @@
     <TextView android:id="@+id/sensor_value"
               android:background="@drawable/gray_bubble"
               android:drawablePadding="10dip"
+              android:layout_above="@+id/sensor_accuracy_value"
+              android:layout_centerInParent="true"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_marginBottom="10dip"
+              android:paddingLeft="10dip"
+              android:paddingRight="10dip"
+              android:paddingTop="5dip"
+              android:paddingBottom="5dip"
+              android:textSize="28dip"
+        />
+
+    <TextView android:id="@+id/sensor_accuracy_value"
+              android:background="@drawable/gray_bubble"
+              android:drawablePadding="10dip"
               android:layout_above="@+id/pass_fail_buttons"
               android:layout_centerInParent="true"
               android:layout_width="wrap_content"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index b6c846f..d93649e 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -412,7 +412,7 @@
 
     <!-- Heart Rate -->
     <string name="snsr_heartrate_test">Heart Rate Test</string>
-    <string name="snsr_heartrate_test_info">This test verifies that the heart rate monitor is working properly.\n\nVerify that the resting heart rate is between 0 and 100.</string>
+    <string name="snsr_heartrate_test_info">This test verifies that the heart rate monitor is working properly.\n\nWait for at least 1 minute before verifying.\n\nVerify that the resting heart rate is between 0 and 100.</string>
     <string name="snsr_heartrate_test_no_heartrate_title">No heart rate monitor?</string>
     <string name="snsr_heartrate_test_no_heartrate_message">It doesn\'t seem like you have a heart rate monitor, so you don\'t need to run this test.</string>
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index e7bf70d..ef80b5d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -23,8 +23,11 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnCancelListener;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -86,6 +89,25 @@
     }
 
     public static class Activity extends android.app.Activity implements PassFailActivity {
+        private WakeLock mWakeLock;
+
+        @Override
+        protected void onResume() {
+            super.onResume();
+            if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+                mWakeLock = ((PowerManager) getSystemService(Context.POWER_SERVICE))
+                        .newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "PassFailButtons");
+                mWakeLock.acquire();
+            }
+        }
+
+        @Override
+        protected void onPause() {
+            super.onPause();
+            if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+                mWakeLock.release();
+            }
+        }
 
         @Override
         public void setPassFailButtonClickListeners() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/HeartRateMonitorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/HeartRateMonitorTestActivity.java
index d0cf41f..3a48e3c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/HeartRateMonitorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/HeartRateMonitorTestActivity.java
@@ -23,7 +23,6 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
 
@@ -93,20 +92,23 @@
         public void onSensorChanged(SensorEvent sensorEvent) {
             float value = sensorEvent.values[0];
             if (value > MAX_HEART_RATE || value < MIN_HEART_RATE) {
-                updateWidgets(value, R.drawable.fs_error);
+                updateWidgets(value, sensorEvent.accuracy, R.drawable.fs_error);
             } else {
-                updateWidgets(value, R.drawable.fs_good);
+                updateWidgets(value, sensorEvent.accuracy, R.drawable.fs_good);
             }
         }
 
-        void updateWidgets(float sensorValue, int icon) {
-            mSensorText.setText(String.format("%+.2f", sensorValue));
-            mSensorText.setCompoundDrawablesWithIntrinsicBounds(0, 0, icon, 0);
+        void updateWidgets(float value, float accuracy, int icon) {
+            TextView sensorText = (TextView) findViewById(R.id.sensor_value);
+            TextView sensorAccuracyText = (TextView) findViewById(R.id.sensor_accuracy_value);
+
+            sensorText.setText(String.format("%+.2f", value));
+            sensorText.setCompoundDrawablesWithIntrinsicBounds(0, 0, icon, 0);
+            sensorAccuracyText.setText(String.format("%+.2f", accuracy));
         }
 
         @Override
         public void onAccuracyChanged(Sensor sensor, int i) {
-
         }
     }
 }
diff --git a/common/host-side/java-scanner/Android.mk b/common/host-side/java-scanner/Android.mk
index 3acf988..7c101ff 100644
--- a/common/host-side/java-scanner/Android.mk
+++ b/common/host-side/java-scanner/Android.mk
@@ -18,12 +18,12 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_JAVA_LIBRARIES := compatibility-common-util-hostsidelib_v2
+
 LOCAL_JAR_MANIFEST := MANIFEST.mf
 
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 
-LOCAL_JAVA_LIBRARIES := junit
-
 LOCAL_MODULE := compatibility-java-scanner_v2
 
 LOCAL_MODULE_TAGS := optional
diff --git a/common/host-side/java-scanner/MANIFEST.mf b/common/host-side/java-scanner/MANIFEST.mf
index a04249a..975b1ef 100644
--- a/common/host-side/java-scanner/MANIFEST.mf
+++ b/common/host-side/java-scanner/MANIFEST.mf
@@ -1,2 +1,3 @@
 Manifest-Version: 1.0
 Main-Class: com.android.compatibility.common.scanner.JavaScanner
+Class-Path: compatibility-common-util-hostsidelib_v2.jar
diff --git a/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScanner.java b/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScanner.java
index c423290..f3f8a49 100644
--- a/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScanner.java
+++ b/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScanner.java
@@ -16,12 +16,15 @@
 
 package com.android.compatibility.common.scanner;
 
+import com.android.compatibility.common.util.KeyValueArgsParser;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -56,7 +59,7 @@
     }
 
     int scan() throws Exception {
-        final List<String> args = new ArrayList<String>();
+        final ArrayList<String> args = new ArrayList<String>();
         args.add("javadoc");
         args.add("-doclet");
         args.add("com.android.compatibility.common.scanner.JavaScannerDoclet");
@@ -90,7 +93,7 @@
     }
 
     private static String getSourcePath(File sourceDir) {
-        List<String> sourcePath = new ArrayList<String>(Arrays.asList(SOURCE_PATHS));
+        final ArrayList<String> sourcePath = new ArrayList<String>(Arrays.asList(SOURCE_PATHS));
         sourcePath.add(sourceDir.toString());
         return join(sourcePath, ":");
     }
@@ -99,8 +102,8 @@
         return join(Arrays.asList(CLASS_PATHS), ":");
     }
 
-    private static List<String> getSourceFiles(File sourceDir) {
-        List<String> sourceFiles = new ArrayList<String>();
+    private static ArrayList<String> getSourceFiles(File sourceDir) {
+        final ArrayList<String> sourceFiles = new ArrayList<String>();
         final File[] files = sourceDir.listFiles(new FileFilter() {
             public boolean accept(File pathname) {
                 return pathname.isDirectory() || pathname.toString().endsWith(".java");
@@ -117,7 +120,7 @@
     }
 
     private static String join(List<String> list, String delimiter) {
-        StringBuilder builder = new StringBuilder();
+        final StringBuilder builder = new StringBuilder();
         for (String s : list) {
             builder.append(s);
             builder.append(delimiter);
@@ -128,19 +131,18 @@
     }
 
     public static void main(String[] args) throws Exception {
-        String sourcePath = null;
-        String docletPath = null;
-        for (int i = 0; i < args.length; i++) {
-            if (args[i].equals("-s") && ++i < args.length) {
-                sourcePath = args[i];
-            } else if (args[i].equals("-d") && ++i < args.length) {
-                docletPath = args[i];
-            }
-        }
+        final HashMap<String, String> argsMap = KeyValueArgsParser.parse(args);
+        final String sourcePath = argsMap.get("-s");
+        final String docletPath = argsMap.get("-d");
         if (sourcePath == null || docletPath == null) {
-            System.err.println("Usage: javascanner -s SOURCE_DIR -d DOCLET_PATH");
-            System.exit(1);
+            usage(args);
         }
         System.exit(new JavaScanner(new File(sourcePath), new File(docletPath)).scan());
     }
+
+    private static void usage(String[] args) {
+        System.err.println("Arguments: " + Arrays.toString(args));
+        System.err.println("Usage: javascanner -s SOURCE_DIR -d DOCLET_PATH");
+        System.exit(1);
+    }
 }
diff --git a/common/host-side/java-scanner/tests/src/com/android/compatibility/common/scanner/JavaScannerTest.java b/common/host-side/java-scanner/tests/src/com/android/compatibility/common/scanner/JavaScannerTest.java
index e18cf16..4159f0e 100644
--- a/common/host-side/java-scanner/tests/src/com/android/compatibility/common/scanner/JavaScannerTest.java
+++ b/common/host-side/java-scanner/tests/src/com/android/compatibility/common/scanner/JavaScannerTest.java
@@ -21,7 +21,6 @@
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.List;
 
 import junit.framework.TestCase;
 
@@ -100,7 +99,7 @@
             out.print(content);
             out.flush();
             out.close();
-            List<String> args = new ArrayList<String>();
+            ArrayList<String> args = new ArrayList<String>();
             args.add("java");
             args.add("-jar");
             args.add(JAR);
diff --git a/common/host-side/native-scanner/Android.mk b/common/host-side/native-scanner/Android.mk
index 8d3242f..184cdc0 100644
--- a/common/host-side/native-scanner/Android.mk
+++ b/common/host-side/native-scanner/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 
-LOCAL_JAVA_LIBRARIES := junit
+LOCAL_JAVA_LIBRARIES := compatibility-common-util-hostsidelib_v2
 
 LOCAL_MODULE := compatibility-native-scanner_v2
 
diff --git a/common/host-side/native-scanner/MANIFEST.mf b/common/host-side/native-scanner/MANIFEST.mf
index 86a7212..c5641ca 100644
--- a/common/host-side/native-scanner/MANIFEST.mf
+++ b/common/host-side/native-scanner/MANIFEST.mf
@@ -1,2 +1,3 @@
 Manifest-Version: 1.0
 Main-Class: com.android.compatibility.common.scanner.NativeScanner
+Class-Path: compatibility-common-util-hostsidelib_v2.jar
diff --git a/common/host-side/native-scanner/src/com/android/compatibility/common/scanner/NativeScanner.java b/common/host-side/native-scanner/src/com/android/compatibility/common/scanner/NativeScanner.java
index 581ee0b..7b9e447 100644
--- a/common/host-side/native-scanner/src/com/android/compatibility/common/scanner/NativeScanner.java
+++ b/common/host-side/native-scanner/src/com/android/compatibility/common/scanner/NativeScanner.java
@@ -16,15 +16,69 @@
 
 package com.android.compatibility.common.scanner;
 
+import com.android.compatibility.common.util.KeyValueArgsParser;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+
 /**
  * Passes the gtest output and outputs a list of test classes and methods.
  */
-public class NativeScanner {
+public final class NativeScanner {
 
-    public static void main(String[] args) throws Exception {
-        // TODO(stuartscott): Parse the gtest output comming from System.in and output in the format
-        // suite:com.android.sample.cts
-        // case:SampleDeviceTest
-        // test:testSharedPreferences
+    private static final String TEST_SUITE_ARG = "t";
+    private static final String USAGE = "Usage: compatibility-native-scanner -t TEST_SUITE"
+        + "  This code reads from stdin the list of tests."
+        + "  The format expected:"
+        + "    TEST_CASE_NAME."
+        + "      TEST_NAME";
+
+    /**
+     * @return An {@link ArrayList} of suites, classes and method names.
+     */
+    static ArrayList<String> getTestNames(BufferedReader reader, String testSuite)
+            throws IOException {
+        ArrayList<String> testNames = new ArrayList<String>();
+        testNames.add("suite:" + testSuite);
+
+        String testCaseName = null;
+        String line;
+        while ((line = reader.readLine()) != null) {
+            if (line.length() == 0) {
+                continue;
+            }
+            if (line.charAt(0) == ' ') {
+                if (testCaseName == null) {
+                    throw new RuntimeException("TEST_CASE_NAME not defined before first test.");
+                }
+                testNames.add("test:" + line.trim());
+            } else {
+                testCaseName = line.trim();
+                if (testCaseName.endsWith(".")) {
+                    testCaseName = testCaseName.substring(0, testCaseName.length()-1);
+                }
+                testNames.add("case:" + testCaseName);
+            }
+        }
+        return testNames;
+    }
+
+    /** Lookup test suite argument and scan {@code System.in} for test cases */
+    public static void main(String[] args) throws IOException {
+        HashMap<String, String> argMap = KeyValueArgsParser.parse(args);
+        if (!argMap.containsKey(TEST_SUITE_ARG)) {
+            System.err.println(USAGE);
+            System.exit(1);
+        }
+
+        String testSuite = argMap.get(TEST_SUITE_ARG);
+
+        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+        for (String name : getTestNames(reader, testSuite)) {
+            System.out.println(name);
+        }
     }
 }
diff --git a/common/host-side/native-scanner/tests/src/com/android/compatibility/common/scanner/NativeScannerTest.java b/common/host-side/native-scanner/tests/src/com/android/compatibility/common/scanner/NativeScannerTest.java
index 3e9ba17..c5d3157 100644
--- a/common/host-side/native-scanner/tests/src/com/android/compatibility/common/scanner/NativeScannerTest.java
+++ b/common/host-side/native-scanner/tests/src/com/android/compatibility/common/scanner/NativeScannerTest.java
@@ -16,10 +16,55 @@
 
 package com.android.compatibility.common.scanner;
 
+import com.android.compatibility.common.scanner.NativeScanner;
+
 import junit.framework.TestCase;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+import java.util.Iterator;
+
 public class NativeScannerTest extends TestCase {
 
-    // TODO(stuartscott): Add tests when there is something to test.
+    public void testSingleTestNamesCase() throws Exception {
+        StringReader singleTestString = new StringReader("FakeTestCase.\n  FakeTestName\n");
+        BufferedReader reader = new BufferedReader(singleTestString);
 
+        List<String> names = NativeScanner.getTestNames(reader, "TestSuite");
+        Iterator<String> it = names.iterator();
+        assertEquals("suite:TestSuite", it.next());
+        assertEquals("case:FakeTestCase", it.next());
+        assertEquals("test:FakeTestName", it.next());
+        assertFalse(it.hasNext());
+    }
+
+    public void testMultipleTestNamesCase() throws Exception {
+        StringReader singleTestString = new StringReader(
+          "Case1.\n  Test1\n  Test2\nCase2.\n  Test3\n Test4\n");
+        BufferedReader reader = new BufferedReader(singleTestString);
+
+        List<String> names = NativeScanner.getTestNames(reader, "TestSuite");
+
+        Iterator<String> it = names.iterator();
+        assertEquals("suite:TestSuite", it.next());
+        assertEquals("case:Case1", it.next());
+        assertEquals("test:Test1", it.next());
+        assertEquals("test:Test2", it.next());
+        assertEquals("case:Case2", it.next());
+        assertEquals("test:Test3", it.next());
+        assertEquals("test:Test4", it.next());
+        assertFalse(it.hasNext());
+    }
+
+    public void testMissingTestCaseNameCase() throws IOException {
+        StringReader singleTestString = new StringReader("  Test1\n");
+        BufferedReader reader = new BufferedReader(singleTestString);
+
+        try {
+            NativeScanner.getTestNames(reader, "TestSuite");
+            fail("Expected RuntimeException");
+        } catch (RuntimeException expected) {}
+    }
 }
diff --git a/common/host-side/scripts/compatibility-tests_v2 b/common/host-side/scripts/compatibility-tests_v2
index b9e479a..797909e 100755
--- a/common/host-side/scripts/compatibility-tests_v2
+++ b/common/host-side/scripts/compatibility-tests_v2
@@ -22,17 +22,17 @@
 }
 
 HOST_JAR_DIR=${ANDROID_HOST_OUT}/framework
-HOST_JARS="ddmlib-prebuilt.jar tradefed-prebuilt.jar hosttestlib.jar\
-    compatibility-tradefed_v2.jar compatibility-tradefed-tests_v2.jar\
-    compatibility-java-scanner_v2.jar compatibility-java-scanner-tests_v2.jar\
-    compatibility-native-scanner_v2.jar compatibility-native-scanner-tests_v2.jar\
-    compatibility-xml-plan-generator_v2.jar compatibility-xml-plan-generator-tests_v2.jar\
-    compatibility-device-util-tests_v2.jar compatibility-device-setup-tests_v2.jar\
-    compatibility-common-util-hostsidelib_v2.jar compatibility-common-util-tests_v2.jar"
+HOST_JARS="ddmlib-prebuilt tradefed-prebuilt hosttestlib\
+    compatibility-tradefed_v2 compatibility-tradefed-tests_v2\
+    compatibility-java-scanner_v2 compatibility-java-scanner-tests_v2\
+    compatibility-native-scanner_v2 compatibility-native-scanner-tests_v2\
+    compatibility-xml-plan-generator_v2 compatibility-xml-plan-generator-tests_v2\
+    compatibility-device-util-tests_v2 compatibility-device-setup-tests_v2\
+    compatibility-common-util-hostsidelib_v2 compatibility-common-util-tests_v2"
 
 for JAR in ${HOST_JARS}; do
-    checkFile ${HOST_JAR_DIR}/${JAR}
-    JAR_PATH=${JAR_PATH}:${HOST_JAR_DIR}/${JAR}
+    checkFile ${HOST_JAR_DIR}/${JAR}.jar
+    JAR_PATH=${JAR_PATH}:${HOST_JAR_DIR}/${JAR}.jar
 done
 
 DEVICE_LIBS_DIR=${ANDROID_PRODUCT_OUT}/obj/JAVA_LIBRARIES
diff --git a/common/host-side/xml-plan-generator/Android.mk b/common/host-side/xml-plan-generator/Android.mk
index 36491bd..53718e5 100644
--- a/common/host-side/xml-plan-generator/Android.mk
+++ b/common/host-side/xml-plan-generator/Android.mk
@@ -18,6 +18,10 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_JAVA_LIBRARIES := compatibility-common-util-hostsidelib_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
+
 LOCAL_JAR_MANIFEST := MANIFEST.mf
 
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
diff --git a/common/host-side/xml-plan-generator/MANIFEST.mf b/common/host-side/xml-plan-generator/MANIFEST.mf
index c021388..95aee0d 100644
--- a/common/host-side/xml-plan-generator/MANIFEST.mf
+++ b/common/host-side/xml-plan-generator/MANIFEST.mf
@@ -1,2 +1,3 @@
 Manifest-Version: 1.0
 Main-Class: com.android.compatibility.common.xmlgenerator.XmlPlanGenerator
+Class-Path: compatibility-common-util-hostsidelib_v2.jar
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/Test.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/Test.java
new file mode 100644
index 0000000..d3e1d88
--- /dev/null
+++ b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/Test.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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.compatibility.common.xmlgenerator;
+
+public class Test {
+
+    private final String mName;
+
+    public Test(String name) {
+        mName = name;
+    }
+
+    public String getName() {
+        return mName;
+    }
+}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestCase.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestCase.java
new file mode 100644
index 0000000..65b4aa3
--- /dev/null
+++ b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestCase.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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.compatibility.common.xmlgenerator;
+
+import java.util.ArrayList;
+
+public class TestCase {
+
+    private final String mName;
+    private final ArrayList<Test> mTests = new ArrayList<Test>();
+
+    public TestCase(String name) {
+        mName = name;
+    }
+
+    public void addTest(Test test) {
+        mTests.add(test);
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public ArrayList<Test> getTests() {
+        return mTests;
+    }
+}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestListParser.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestListParser.java
new file mode 100644
index 0000000..6880440
--- /dev/null
+++ b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestListParser.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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.compatibility.common.xmlgenerator;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Scanner;
+
+/**
+ * Parser of test lists in the form;
+ *
+ * suite:android.sample
+ * case:SampleTest
+ * test:testA
+ * test:testB
+ * suite:android.sample.ui
+ * case:SampleUiTest
+ * test:testA
+ * test:testB
+ */
+public class TestListParser {
+
+    private TestListParser() {}
+
+    public static HashMap<String, TestSuite> parse(InputStream input) {
+        final HashMap<String, TestSuite> suites = new HashMap<String, TestSuite>();
+        TestSuite currentSuite = null;
+        TestCase currentCase = null;
+        Scanner in = null;
+        try {
+            in = new Scanner(input);
+            while (in.hasNextLine()) {
+                final String line = in.nextLine();
+                final String[] parts = line.split(":");
+                if (parts.length != 2) {
+                    throw new RuntimeException("Invalid Format: " + line);
+                }
+                final String key = parts[0];
+                final String value = parts[1];
+                if (currentSuite == null) {
+                    if (!"suite".equals(key)) {
+                        throw new RuntimeException("TestSuite Expected");
+                    }
+                    final String[] names = value.split("\\.");
+                    for (int i = 0; i < names.length; i++) {
+                        final String name = names[i];
+                        if (currentSuite != null) {
+                            if (currentSuite.hasTestSuite(name)) {
+                                currentSuite = currentSuite.getTestSuite(name);
+                            } else {
+                                final TestSuite newSuite = new TestSuite(name);
+                                currentSuite.addTestSuite(newSuite);
+                                currentSuite = newSuite;
+                            }
+                        } else if (suites.containsKey(name)) {
+                            currentSuite = suites.get(name);
+                        } else {
+                            currentSuite = new TestSuite(name);
+                            suites.put(name, currentSuite);
+                        }
+                    }
+                } else if (currentCase == null) {
+                    if (!"case".equals(key)) {
+                        throw new RuntimeException("TestCase Expected");
+                    }
+                    currentCase = new TestCase(value);
+                    currentSuite.addTestCase(currentCase);
+                } else {
+                    if (!"test".equals(key)) {
+                        throw new RuntimeException("Test Expected");
+                    }
+                    currentCase.addTest(new Test(value));
+                }
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+        return suites;
+    }
+}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestSuite.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestSuite.java
new file mode 100644
index 0000000..db4fd07
--- /dev/null
+++ b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestSuite.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 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.compatibility.common.xmlgenerator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class TestSuite {
+
+    private final String mName;
+    private final HashMap<String, TestSuite> mTestSuites = new HashMap<String, TestSuite>();
+    private final ArrayList<TestCase> mTestCases = new ArrayList<TestCase>();
+
+    public TestSuite(String name) {
+        mName = name;
+    }
+
+    public boolean hasTestSuite(String name) {
+        return mTestSuites.containsKey(name);
+    }
+
+    public TestSuite getTestSuite(String name) {
+        return mTestSuites.get(name);
+    }
+
+    public void addTestSuite(TestSuite testSuite) {
+        mTestSuites.put(testSuite.getName(), testSuite);
+    }
+
+    public void addTestCase(TestCase testCase) {
+        mTestCases.add(testCase);
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public HashMap<String, TestSuite> getTestSuites() {
+        return mTestSuites;
+    }
+
+    public ArrayList<TestCase> getTestCases() {
+        return mTestCases;
+    }
+}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
index 510c935..d0a3a37 100644
--- a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
+++ b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
@@ -16,12 +16,202 @@
 
 package com.android.compatibility.common.xmlgenerator;
 
+import com.android.compatibility.common.util.KeyValueArgsParser;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import vogar.Expectation;
+import vogar.ExpectationStore;
+import vogar.ModeId;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+
 /**
  * Passes the scanner output and outputs an xml description of the tests.
  */
 public class XmlPlanGenerator {
 
+    private final ExpectationStore mExpectations;
+    private final String mAppNameSpace;
+    private final String mAppPackageName;
+    private final String mName;
+    private final String mRunner;
+    private final String mTargetBinaryName;
+    private final String mTargetNameSpace;
+    private final String mJarPath;
+    private final String mTestType;
+    private final String mOutput;
+
+    private XmlPlanGenerator(ExpectationStore expectations, String appNameSpace,
+            String appPackageName, String name, String runner, String targetBinaryName,
+            String targetNameSpace, String jarPath, String testType, String output) {
+        mExpectations = expectations;
+        mAppNameSpace = appNameSpace;
+        mAppPackageName = appPackageName;
+        mName = name;
+        mRunner = runner;
+        mTargetBinaryName = targetBinaryName;
+        mTargetNameSpace = targetNameSpace;
+        mJarPath = jarPath;
+        mTestType = testType;
+        mOutput = output;
+    }
+
+    private void writePackageXml() throws IOException {
+        OutputStream out = System.out;
+        if (mOutput != null) {
+            out = new FileOutputStream(mOutput);
+        }
+        PrintWriter writer = null;
+        try {
+            writer = new PrintWriter(out);
+            writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+            writeTestPackage(writer);
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    private void writeTestPackage(PrintWriter writer) {
+        writer.append("<TestPackage");
+        if (mAppNameSpace != null) {
+            writer.append(" appNameSpace=\"").append(mAppNameSpace).append("\"");
+        }
+
+        writer.append(" appPackageName=\"").append(mAppPackageName).append("\"");
+        writer.append(" name=\"").append(mName).append("\"");
+
+        if (mRunner != null) {
+            writer.append(" runner=\"").append(mRunner).append("\"");
+        }
+
+        if (mAppNameSpace != null && mTargetNameSpace != null
+                && !mAppNameSpace.equals(mTargetNameSpace)) {
+            writer.append(" targetBinaryName=\"").append(mTargetBinaryName).append("\"");
+            writer.append(" targetNameSpace=\"").append(mTargetNameSpace).append("\"");
+        }
+
+        if (mTestType != null && !mTestType.isEmpty()) {
+            writer.append(" testType=\"").append(mTestType).append("\"");
+        }
+
+        if (mJarPath != null) {
+            writer.append(" jarPath=\"").append(mJarPath).append("\"");
+        }
+
+        writer.println(" version=\"1.0\">");
+
+        final HashMap<String, TestSuite> suites = TestListParser.parse(System.in);
+        if (suites.isEmpty()) {
+            throw new RuntimeException("No TestSuites Found");
+        }
+        writeTestSuites(writer, suites, "");
+        writer.println("</TestPackage>");
+    }
+
+    private void writeTestSuites(PrintWriter writer, HashMap<String, TestSuite> suites, String name) {
+        for (String suiteName : suites.keySet()) {
+            final TestSuite suite = suites.get(suiteName);
+            writer.append("<TestSuite name=\"").append(suiteName).println("\">");
+            final String fullname = name + suiteName + ".";
+            writeTestSuites(writer, suite.getTestSuites(), fullname);
+            writeTestCases(writer, suite.getTestCases(), fullname);
+            writer.println("</TestSuite>");
+        }
+    }
+
+    private void writeTestCases(PrintWriter writer, ArrayList<TestCase> cases, String name) {
+        for (TestCase testCase : cases) {
+            final String caseName = testCase.getName();
+            writer.append("<TestCase name=\"").append(caseName).println("\">");
+            final String fullname = name + caseName;
+            writeTests(writer, testCase.getTests(), fullname);
+            writer.println("</TestCase>");
+        }
+    }
+
+    private void writeTests(PrintWriter writer, ArrayList<Test> tests, String name) {
+        if (tests.isEmpty()) {
+            throw new RuntimeException("No Tests Found");
+        }
+        for (Test test : tests) {
+            final String testName = test.getName();
+            writer.append("<Test name=\"").append(testName).append("\"");
+            final String fullname = name + "#" + testName;
+            if (isKnownFailure(mExpectations, fullname)) {
+                writer.append(" expectation=\"failure\"");
+            }
+            writer.println(" />");
+        }
+    }
+
+    public static boolean isKnownFailure(ExpectationStore store, String fullname) {
+        return store != null && store.get(fullname) != Expectation.SUCCESS;
+    }
+
     public static void main(String[] args) throws Exception {
-        // TODO(stuartscott)
+        final HashMap<String, String> argsMap = KeyValueArgsParser.parse(args);
+        final String packageName = argsMap.get("-p");
+        final String name = argsMap.get("-n");
+        final String testType = argsMap.get("-t");
+        final String jarPath = argsMap.get("-j");
+        final String instrumentation = argsMap.get("-i");
+        final String manifest = argsMap.get("-m");
+        final String expectations = argsMap.get("-e");
+        final String output = argsMap.get("-o");
+        String appNameSpace = argsMap.get("-a");
+        String targetNameSpace = argsMap.get("-r");
+        if (packageName == null || name == null) {
+            usage(args);
+        }
+        String runner = null;
+        if (manifest != null) {
+            Document m = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(manifest);
+            Element elem = m.getDocumentElement();
+            appNameSpace = elem.getAttribute("package");
+            runner = getElementAttribute(elem, "instrumentation", "android:name");
+            targetNameSpace = getElementAttribute(elem, "instrumentation", "android:targetPackage");
+        }
+
+        final HashSet<File> expectationFiles = new HashSet<File>();
+        if (expectations != null) {
+            expectationFiles.add(new File(expectations));
+        }
+        final ExpectationStore store = ExpectationStore.parse(expectationFiles, ModeId.DEVICE);
+        XmlPlanGenerator generator = new XmlPlanGenerator(store, appNameSpace, packageName, name,
+            runner, instrumentation, targetNameSpace, jarPath, testType, output);
+        generator.writePackageXml();
+    }
+
+    private static String getElementAttribute(Element parent, String elem, String name) {
+        NodeList nodeList = parent.getElementsByTagName(elem);
+        if (nodeList.getLength() > 0) {
+             Element element = (Element) nodeList.item(0);
+             return element.getAttribute(name);
+        }
+        return null;
+    }
+
+    private static void usage(String[] args) {
+        System.err.println("Arguments: " + Arrays.toString(args));
+        System.err.println("Usage: compatibility-xml-plan-generator -p PACKAGE_NAME -n NAME" +
+            "[-t TEST_TYPE] [-j JAR_PATH] [-i INSTRUMENTATION] [-m MANIFEST] [-e EXPECTATIONS]" +
+            "[-o OUTPUT]");
+        System.exit(1);
     }
 }
diff --git a/common/host-side/xml-plan-generator/tests/src/com/android/compatibility/common/xmlgenerator/XmlPlanGeneratorTest.java b/common/host-side/xml-plan-generator/tests/src/com/android/compatibility/common/xmlgenerator/XmlPlanGeneratorTest.java
index 35bcb02..082af17 100644
--- a/common/host-side/xml-plan-generator/tests/src/com/android/compatibility/common/xmlgenerator/XmlPlanGeneratorTest.java
+++ b/common/host-side/xml-plan-generator/tests/src/com/android/compatibility/common/xmlgenerator/XmlPlanGeneratorTest.java
@@ -18,7 +18,111 @@
 
 import junit.framework.TestCase;
 
+import java.io.ByteArrayInputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Scanner;
+
 public class XmlPlanGeneratorTest extends TestCase {
 
-    // TODO(stuartscott): Add tests when there is something to test.
+    private static final String JAR = "out/host/linux-x86/framework/compatibility-xml-plan-generator_v2.jar";
+    private static final String PACKAGE_NAME = "com.android.test";
+    private static final String NAME = "ValidTest";
+    private static final String VALID_RESULT =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+        "<TestPackage appPackageName=\"com.android.test\" name=\"ValidTest\" version=\"1.0\">" +
+        "<TestSuite name=\"com\">" +
+        "<TestSuite name=\"android\">" +
+        "<TestSuite name=\"test\">" +
+        "<TestCase name=\"ValidTest\">" +
+        "<Test name=\"testA\" />" +
+        "</TestCase>" +
+        "</TestSuite>" +
+        "</TestSuite>" +
+        "</TestSuite>" +
+        "</TestPackage>";
+
+    private static final String VALID =
+        "suite:com.android.test\n" +
+        "case:ValidTest\n" +
+        "test:testA\n";
+
+    private static final String INVALID_A = "";
+
+    private static final String INVALID_B =
+        "suite:com.android.test\n" +
+        "case:InvalidTest\n";
+
+    private static final String INVALID_C =
+        "uh oh";
+
+    private static final String INVALID_D =
+        "test:testA\n" +
+        "case:InvalidTest\n" +
+        "suite:com.android.test\n";
+
+    private static final String INVALID_E =
+        "suite:com.android.test\n" +
+        "test:testA\n" +
+        "case:InvalidTest\n";
+
+    public void testValid() throws Exception {
+        assertEquals(VALID_RESULT, runGenerator(VALID));
+    }
+
+    public void testInvalidA() throws Exception {
+        assertNull(runGenerator(INVALID_A));
+    }
+
+    public void testInvalidB() throws Exception {
+        assertNull(runGenerator(INVALID_B));
+    }
+
+    public void testTestListParserInvalidFormat() throws Exception {
+        runTestListParser(INVALID_C);
+    }
+
+    public void testTestListParserSuiteExpected() throws Exception {
+        runTestListParser(INVALID_D);
+    }
+
+    public void testTestListParserCaseExpected() throws Exception {
+        runTestListParser(INVALID_E);
+    }
+
+    private static String runGenerator(String input) throws Exception {
+        ArrayList<String> args = new ArrayList<String>();
+        args.add("java");
+        args.add("-jar");
+        args.add(JAR);
+        args.add("-p");
+        args.add(PACKAGE_NAME);
+        args.add("-n");
+        args.add(NAME);
+
+        final Process p = new ProcessBuilder(args).start();
+        final PrintWriter out = new PrintWriter(p.getOutputStream());
+        out.print(input);
+        out.flush();
+        out.close();
+        final StringBuilder output = new StringBuilder();
+        final Scanner in = new Scanner(p.getInputStream());
+        while (in.hasNextLine()) {
+            output.append(in.nextLine());
+        }
+        int ret = p.waitFor();
+        if (ret == 0) {
+            return output.toString();
+        }
+        return null;
+    }
+
+    private static void runTestListParser(String input) throws Exception {
+        try {
+            final ByteArrayInputStream in = new ByteArrayInputStream(input.getBytes());
+            final HashMap<String, TestSuite> suites = TestListParser.parse(in);
+            fail();
+        } catch (RuntimeException e) {}
+    }
 }
diff --git a/common/util/src/com/android/compatibility/common/util/KeyValueArgsParser.java b/common/util/src/com/android/compatibility/common/util/KeyValueArgsParser.java
new file mode 100644
index 0000000..92a2b18
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/KeyValueArgsParser.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 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.compatibility.common.util;
+
+import java.util.HashMap;
+
+/**
+ * Parses an array of arguments into a HashMap.
+ *
+ * This class assumed the arguments are in the form "-<key> <value> ..."
+ */
+public class KeyValueArgsParser {
+
+    private KeyValueArgsParser() {}
+
+    public static HashMap<String, String> parse(String[] args) {
+        final HashMap<String, String> map = new HashMap<String, String>();
+        String key = null;
+        for (String s : args) {
+            if (key == null) {
+                if (!s.startsWith("-")) {
+                    throw new RuntimeException("Invalid Key: " + s);
+                }
+                key = s;
+            } else {
+                map.put(key, s);
+                key = null;
+            }
+        }
+        if (key != null) {
+            throw new RuntimeException("Left over key");
+        }
+        return map;
+    }
+}
diff --git a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/opengl/CtsDeviceJankOpenGl.java b/suite/cts/hostTests/jank/app/src/com/android/cts/jank/opengl/CtsDeviceJankOpenGl.java
old mode 100644
new mode 100755
index fbe3cd6..5ba0613
--- a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/opengl/CtsDeviceJankOpenGl.java
+++ b/suite/cts/hostTests/jank/app/src/com/android/cts/jank/opengl/CtsDeviceJankOpenGl.java
@@ -63,7 +63,7 @@
         sb.append(String.format(START_CMD, COMPONENT));
         sb.append(String.format(INTENT_STRING_EXTRA, "benchmark_name", benchmark));
         sb.append(String.format(INTENT_BOOLEAN_EXTRA, "offscreen", false));
-        sb.append(String.format(INTENT_INTEGER_EXTRA, "num_frames", 400));
+        sb.append(String.format(INTENT_INTEGER_EXTRA, "num_frames", 1000));
         sb.append(String.format(INTENT_INTEGER_EXTRA, "num_iterations", 1));
         sb.append(String.format(INTENT_INTEGER_EXTRA, "timeout", 10000));
         final String startCommand = sb.toString();
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index cc5832c..522eb6e 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -117,6 +117,9 @@
     <!-- Used for Transmit IR Test -->
     <uses-permission android:name="android.permission.TRANSMIT_IR" />
 
+    <!-- Used for SystemFeatures Test -->
+    <uses-permission android:name="android.permission.BODY_SENSORS"/>
+
     <!-- Used for PackageManager test, don't delete this permission-tree -->
     <permission-tree android:name="com.android.cts.stub.permission.TEST_DYNAMIC"
                     android:label="Test Tree"/>
diff --git a/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java b/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java
index a142b29..21ef195 100644
--- a/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java
+++ b/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java
@@ -35,6 +35,7 @@
 import java.net.CookieHandler;
 import java.net.ResponseCache;
 import java.util.Locale;
+import java.util.TimeZone;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
@@ -154,14 +155,16 @@
 
     // http://code.google.com/p/vogar/source/browse/trunk/src/vogar/target/TestEnvironment.java
     static class TestEnvironment {
-        private Locale mDefaultLocale;
-        private String mUserHome;
-        private String mJavaIoTmpDir;
-        private HostnameVerifier mHostnameVerifier;
-        private SSLSocketFactory mSslSocketFactory;
+        private final Locale mDefaultLocale;
+        private final TimeZone mDefaultTimeZone;
+        private final String mUserHome;
+        private final String mJavaIoTmpDir;
+        private final HostnameVerifier mHostnameVerifier;
+        private final SSLSocketFactory mSslSocketFactory;
 
         TestEnvironment() {
             mDefaultLocale = Locale.getDefault();
+            mDefaultTimeZone = TimeZone.getDefault();
             mUserHome = System.getProperty("user.home");
             mJavaIoTmpDir = System.getProperty("java.io.tmpdir");
             mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
@@ -170,6 +173,7 @@
 
         void reset() {
             Locale.setDefault(mDefaultLocale);
+            TimeZone.setDefault(mDefaultTimeZone);
             System.setProperty("user.home", mUserHome);
             System.setProperty("java.io.tmpdir", mJavaIoTmpDir);
             Authenticator.setDefault(null);
diff --git a/tests/jni/Android.mk b/tests/jni/Android.mk
index 28aa15a..139118d 100644
--- a/tests/jni/Android.mk
+++ b/tests/jni/Android.mk
@@ -30,7 +30,7 @@
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
-LOCAL_SHARED_LIBRARIES := libnativehelper liblog
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libdl
 
 LOCAL_SRC_FILES += android_os_cts_CpuFeatures.cpp
 LOCAL_C_INCLUDES += ndk/sources/cpufeatures
diff --git a/tests/res/drawable/touchfeedbackdrawable_theme.xml b/tests/res/drawable/rippledrawable_theme.xml
similarity index 90%
rename from tests/res/drawable/touchfeedbackdrawable_theme.xml
rename to tests/res/drawable/rippledrawable_theme.xml
index a2b73cd..0a9d6c0 100644
--- a/tests/res/drawable/touchfeedbackdrawable_theme.xml
+++ b/tests/res/drawable/rippledrawable_theme.xml
@@ -15,5 +15,5 @@
      limitations under the License.
 -->
 
-<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
     android:tint="?attr/themeColor" />
diff --git a/tests/src/android/opengl/cts/EglConfigStubActivity.java b/tests/src/android/opengl/cts/EglConfigStubActivity.java
index ab1a6d0..749679a 100644
--- a/tests/src/android/opengl/cts/EglConfigStubActivity.java
+++ b/tests/src/android/opengl/cts/EglConfigStubActivity.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.opengl.GLSurfaceView;
 import android.os.Bundle;
+import android.view.WindowManager;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -44,6 +45,11 @@
         int contextClientVersion = getContextClientVersion();
         setTitle("EGL Config Id: " + configId + " Client Version: " + contextClientVersion);
 
+        // Dismiss keyguard and keep screen on while this test is on.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
+                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
         mFinishedDrawing = new CountDownLatch(1);
         mView = new EglConfigGLSurfaceView(this, configId, contextClientVersion, new Runnable() {
             @Override
diff --git a/tests/src/android/text/EmojiStubActivity.java b/tests/src/android/text/EmojiStubActivity.java
index 1587c94..8d09250 100644
--- a/tests/src/android/text/EmojiStubActivity.java
+++ b/tests/src/android/text/EmojiStubActivity.java
@@ -21,15 +21,20 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.webkit.WebView;
+import android.webkit.cts.NullWebViewUtils;
 
 public class EmojiStubActivity extends Activity {
     private WebView mWebView;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.webview_layout);
-        mWebView = (WebView) findViewById(R.id.web_page);
+        try {
+            super.onCreate(savedInstanceState);
+            setContentView(R.layout.webview_layout);
+            mWebView = (WebView) findViewById(R.id.web_page);
+        } catch (Exception e) {
+            NullWebViewUtils.determineIfWebViewAvailable(this, e);
+        }
     }
 
     public WebView getWebView() {
@@ -38,7 +43,9 @@
 
     @Override
     public void onDestroy() {
-        mWebView.destroy();
+        if (mWebView != null) {
+            mWebView.destroy();
+        }
         super.onDestroy();
     }
 }
diff --git a/tests/src/android/webkit/cts/CookieSyncManagerStubActivity.java b/tests/src/android/webkit/cts/CookieSyncManagerStubActivity.java
index 3421ac6..a5ac6ec 100644
--- a/tests/src/android/webkit/cts/CookieSyncManagerStubActivity.java
+++ b/tests/src/android/webkit/cts/CookieSyncManagerStubActivity.java
@@ -27,22 +27,35 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        CookieSyncManager.createInstance(this);
 
-        mWebView = new WebView(this);
-        setContentView(mWebView);
+        try {
+            CookieSyncManager.createInstance(this);
+
+            mWebView = new WebView(this);
+            setContentView(mWebView);
+        } catch (Exception e) {
+            NullWebViewUtils.determineIfWebViewAvailable(this, e);
+        }
     }
 
     @Override
     protected void onResume() {
         super.onResume();
-        CookieSyncManager.getInstance().startSync();
+        try {
+            CookieSyncManager.getInstance().startSync();
+        } catch (Exception e) {
+            // May throw on a device with no webview, OK to ignore at this point.
+        }
     }
 
     @Override
     protected void onStop() {
         super.onStop();
-        CookieSyncManager.getInstance().stopSync();
+        try {
+            CookieSyncManager.getInstance().stopSync();
+        } catch (Exception e) {
+            // May throw on a device with no webview, OK to ignore at this point.
+        }
     }
 
     public WebView getWebView(){
diff --git a/tests/src/android/webkit/cts/NullWebViewUtils.java b/tests/src/android/webkit/cts/NullWebViewUtils.java
new file mode 100644
index 0000000..c52219f
--- /dev/null
+++ b/tests/src/android/webkit/cts/NullWebViewUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit.cts;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * Utilities to enable the android.webkit.* CTS tests (and others that rely on a functioning
+ * android.webkit.WebView implementation) to determine whether a functioning WebView is present
+ * on the device or not.
+ *
+ * Test cases that require android.webkit.* classes should wrap their first usage of WebView in a
+ * try catch block, and pass any exception that is thrown to
+ * NullWebViewUtils.determineIfWebViewAvailable. The return value of
+ * NullWebViewUtils.isWebViewAvailable will then determine if the test should expect to be able to
+ * use a WebView.
+ */
+public class NullWebViewUtils {
+
+    private static boolean sWebViewUnavailable;
+
+    /**
+     * @param context Current Activity context, used to query the PackageManager.
+     * @param t       An exception thrown by trying to invoke android.webkit.* APIs.
+     */
+    public static void determineIfWebViewAvailable(Context context, Throwable t) {
+        sWebViewUnavailable = !hasWebViewFeature(context) && checkCauseWasUnsupportedOperation(t);
+    }
+
+    /**
+     * After calling determineIfWebViewAvailable, this returns whether a WebView is available on the
+     * device and wheter the test can rely on it.
+     * @return True iff. PackageManager determined that there is no WebView on the device and the
+     *         exception thrown from android.webkit.* was UnsupportedOperationException.
+     */
+    public static boolean isWebViewAvailable() {
+        return !sWebViewUnavailable;
+    }
+
+    private static boolean hasWebViewFeature(Context context) {
+        // Query the system property that determins if there is a functional WebView on the device.
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW);
+    }
+
+    private static boolean checkCauseWasUnsupportedOperation(Throwable t) {
+        if (t == null) return false;
+        while (t.getCause() != null) {
+            t = t.getCause();
+        }
+        return t instanceof UnsupportedOperationException;
+    }
+
+    /**
+     * Some CTS tests (by design) first use android.webkit.* from a background thread. This helper
+     * allows the test to catch the UnsupportedOperationException from that background thread, and
+     * then query the result from the test main thread.
+     */
+    public static class NullWebViewFromThreadExceptionHandler
+            implements Thread.UncaughtExceptionHandler {
+        private Throwable mPendingException;
+
+        @Override
+        public void uncaughtException(Thread t, Throwable e) {
+            mPendingException = e;
+        }
+
+        public boolean isWebViewAvailable(Context context) {
+            return hasWebViewFeature(context) ||
+                    !checkCauseWasUnsupportedOperation(mPendingException);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/src/android/webkit/cts/WebViewStubActivity.java b/tests/src/android/webkit/cts/WebViewStubActivity.java
index 6a51bbe..62adc39 100644
--- a/tests/src/android/webkit/cts/WebViewStubActivity.java
+++ b/tests/src/android/webkit/cts/WebViewStubActivity.java
@@ -29,9 +29,13 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.webview_layout);
-        mWebView = (WebView) findViewById(R.id.web_page);
+        try {
+            super.onCreate(savedInstanceState);
+            setContentView(R.layout.webview_layout);
+            mWebView = (WebView) findViewById(R.id.web_page);
+        } catch (Exception e) {
+            NullWebViewUtils.determineIfWebViewAvailable(this, e);
+        }
     }
 
     public WebView getWebView() {
@@ -40,11 +44,13 @@
 
     @Override
     public void onDestroy() {
-        ViewParent parent =  mWebView.getParent();
-        if (parent instanceof ViewGroup) {
-            ((ViewGroup) parent).removeView(mWebView);
+        if (mWebView != null) {
+            ViewParent parent =  mWebView.getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(mWebView);
+            }
+            mWebView.destroy();
         }
-        mWebView.destroy();
         super.onDestroy();
     }
 }
diff --git a/tests/src/android/widget/cts/RemoteViewsStubActivity.java b/tests/src/android/widget/cts/RemoteViewsStubActivity.java
index f1c0a72..f16ae13 100644
--- a/tests/src/android/widget/cts/RemoteViewsStubActivity.java
+++ b/tests/src/android/widget/cts/RemoteViewsStubActivity.java
@@ -20,6 +20,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.webkit.cts.NullWebViewUtils;
 import android.widget.RemoteViews;
 
 /**
@@ -28,7 +29,11 @@
 public class RemoteViewsStubActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.remoteviews_host);
+        try {
+            super.onCreate(savedInstanceState);
+            setContentView(R.layout.remoteviews_host);
+        } catch (Exception e) {
+            NullWebViewUtils.determineIfWebViewAvailable(this, e);
+        }
     }
 }
diff --git a/tests/res/drawable/touchfeedbackdrawable_theme.xml b/tests/tests/accessibility/res/values/ids.xml
similarity index 70%
copy from tests/res/drawable/touchfeedbackdrawable_theme.xml
copy to tests/tests/accessibility/res/values/ids.xml
index a2b73cd..23edb2b 100644
--- a/tests/res/drawable/touchfeedbackdrawable_theme.xml
+++ b/tests/tests/accessibility/res/values/ids.xml
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-    
+<!-- Copyright (C) 2014 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.
@@ -15,5 +13,6 @@
      limitations under the License.
 -->
 
-<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
-    android:tint="?attr/themeColor" />
+<resources>
+    <item type="id" name="foo_custom_action" />
+</resources>
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index ae7cc9b..7925d15 100644
--- a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -23,6 +23,11 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.cts.accessibility.R;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Class for testing {@link AccessibilityNodeInfo}.
@@ -94,6 +99,70 @@
     }
 
     /**
+     * Tests whether accessibility actions are properly added.
+     */
+    @SmallTest
+    public void testAddActions() {
+        List<AccessibilityAction> customActions = new ArrayList<AccessibilityAction>();
+        customActions.add(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
+        customActions.add(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
+
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
+        for (AccessibilityAction customAction : customActions) {
+            info.addAction(customAction);
+        }
+
+        assertSame(info.getActions(), (AccessibilityNodeInfo.ACTION_FOCUS
+                | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS));
+
+        List<AccessibilityAction> allActions = new ArrayList<AccessibilityAction>();
+        allActions.add(AccessibilityAction.ACTION_CLEAR_FOCUS);
+        allActions.addAll(customActions);
+        assertEquals(info.getActionList(), allActions);
+    }
+
+    /**
+     * Tests whether we catch addition of an action with invalid id.
+     */
+    @SmallTest
+    public void testCreateInvalidActionId() {
+        try {
+            new AccessibilityAction(3, null);
+        } catch (IllegalArgumentException iae) {
+            /* expected */
+        }
+    }
+
+    /**
+     * Tests whether accessibility actions are properly removed.
+     */
+    @SmallTest
+    public void testRemoveActions() {
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
+
+        info.removeAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        assertSame(info.getActions(), 0);
+        assertTrue(info.getActionList().isEmpty());
+
+        AccessibilityAction customFocus = new AccessibilityAction(
+                AccessibilityNodeInfo.ACTION_FOCUS, "Foo");
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        info.addAction(customFocus);
+        assertSame(info.getActionList().size(), 1);
+        assertEquals(info.getActionList().get(0), customFocus);
+        assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
+
+        info.removeAction(customFocus);
+        assertSame(info.getActions(), 0);
+        assertTrue(info.getActionList().isEmpty());
+    }
+
+    /**
      * Fully populates the {@link AccessibilityNodeInfo} to marshal.
      *
      * @param info The node info to populate.
@@ -119,7 +188,10 @@
         info.setPassword(true);
         info.setScrollable(true);
         info.setSelected(true);
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
         info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
+        info.addAction(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
+        info.addAction(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
         info.setAccessibilityFocused(true);
         info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
         info.setLabeledBy(new View(getContext()));
@@ -171,6 +243,8 @@
                 receivedInfo.isSelected());
         assertSame("actions has incorrect value", expectedInfo.getActions(),
                 receivedInfo.getActions());
+        assertEquals("actionsSet has incorrect value", expectedInfo.getActionList(),
+                receivedInfo.getActionList());
         assertSame("childCount has incorrect value", expectedInfo.getChildCount(),
                 receivedInfo.getChildCount());
         assertSame("childCount has incorrect value", expectedInfo.getChildCount(),
diff --git a/tests/res/drawable/touchfeedbackdrawable_theme.xml b/tests/tests/accessibilityservice/res/values/ids.xml
similarity index 70%
copy from tests/res/drawable/touchfeedbackdrawable_theme.xml
copy to tests/tests/accessibilityservice/res/values/ids.xml
index a2b73cd..23edb2b 100644
--- a/tests/res/drawable/touchfeedbackdrawable_theme.xml
+++ b/tests/tests/accessibilityservice/res/values/ids.xml
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-    
+<!-- Copyright (C) 2014 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.
@@ -15,5 +13,6 @@
      limitations under the License.
 -->
 
-<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
-    android:tint="?attr/themeColor" />
+<resources>
+    <item type="id" name="foo_custom_action" />
+</resources>
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java
index 6f72a75..698989c 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java
@@ -18,13 +18,15 @@
 import android.os.Bundle;
 import android.view.View;
 
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import com.android.cts.accessibilityservice.R;
 
 /**
  * Activity for testing the accessibility APIs for querying of
  * the screen content. These APIs allow exploring the screen and
  * requesting an action to be performed on a given view from an
- * AccessiiblityService.
+ * AccessibilityService.
  */
 public class AccessibilityWindowQueryActivity extends Activity {
 
@@ -43,5 +45,21 @@
                 return true;
             }
         });
+
+        findViewById(R.id.button5).setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.addAction(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
+            }
+
+            @Override
+            public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                if (action == R.id.foo_custom_action) {
+                    return true;
+                }
+                return super.performAccessibilityAction(host, action, args);
+            }
+        });
     }
 }
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index f01ae7b..b8d543d 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -31,6 +31,7 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityWindowInfo;
 
 import com.android.cts.accessibilityservice.R;
@@ -43,7 +44,7 @@
 /**
  * Test cases for testing the accessibility APIs for querying of the screen content.
  * These APIs allow exploring the screen and requesting an action to be performed
- * on a given view from an AccessiiblityService.
+ * on a given view from an AccessibilityService.
  */
 public class AccessibilityWindowQueryTest
         extends AccessibilityActivityTestCase<AccessibilityWindowQueryActivity> {
@@ -535,6 +536,28 @@
         assertNotNull(expected);
     }
 
+
+    @MediumTest
+    public void testPerformCustomAction() throws Exception {
+        // find a view and make sure it is not selected
+        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+
+        // find the custom action and perform it
+        List<AccessibilityAction> actions = button.getActionList();
+        final int actionCount = actions.size();
+        for (int i = 0; i < actionCount; i++) {
+            AccessibilityAction action = actions.get(i);
+            if (action.getId() == R.id.foo_custom_action) {
+                assertSame(action.getLabel(), "Foo");
+                // perform the action
+                assertTrue(button.performAction(action.getId()));
+                return;
+            }
+        }
+    }
+
     @MediumTest
     public void testGetEventSource() throws Exception {
         // find a view and make sure it is not focused
diff --git a/tests/tests/app/src/android/app/cts/ActionBarActivity.java b/tests/tests/app/src/android/app/cts/ActionBarActivity.java
index 11cee03..dc65cb2 100644
--- a/tests/tests/app/src/android/app/cts/ActionBarActivity.java
+++ b/tests/tests/app/src/android/app/cts/ActionBarActivity.java
@@ -25,6 +25,8 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         ActionBar bar = getActionBar();
-        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+        if (bar != null) {
+            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+        }
     }
 }
diff --git a/tests/tests/app/src/android/app/cts/ActionBarTest.java b/tests/tests/app/src/android/app/cts/ActionBarTest.java
index 796cd74..75e7807 100644
--- a/tests/tests/app/src/android/app/cts/ActionBarTest.java
+++ b/tests/tests/app/src/android/app/cts/ActionBarTest.java
@@ -40,6 +40,9 @@
 
     @UiThreadTest
     public void testAddTab() {
+        if (mBar == null) {
+            return;
+        }
         assertEquals(0, mBar.getTabCount());
 
         Tab t1 = createTab("Tab 1");
diff --git a/tests/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/tests/app/src/android/app/cts/InstrumentationTest.java
index 30cdd5f..16a4ee1 100644
--- a/tests/tests/app/src/android/app/cts/InstrumentationTest.java
+++ b/tests/tests/app/src/android/app/cts/InstrumentationTest.java
@@ -667,6 +667,24 @@
             @Override
             public void takeInputQueue(InputQueue.Callback queue) {
             }
+
+            @Override
+            public void setStatusBarColor(int color) {
+            }
+
+            @Override
+            public int getStatusBarColor() {
+                return 0;
+            }
+
+            @Override
+            public void setNavigationBarColor(int color) {
+            }
+
+            @Override
+            public int getNavigationBarColor() {
+                return 0;
+            }
         }
     }
 
diff --git a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
index d959586..c4318d8 100644
--- a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -237,6 +237,8 @@
                 Sensor.TYPE_STEP_COUNTER);
         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_STEP_DETECTOR,
                 Sensor.TYPE_STEP_DETECTOR);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE,
+                Sensor.TYPE_HEART_RATE);
 
         assertTrue("Assertions need to be added to this test for " + featuresLeft,
                 featuresLeft.isEmpty());
diff --git a/tests/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/tests/app/src/android/app/cts/WallpaperManagerTest.java
index fdf3cac..65f89f3 100644
--- a/tests/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -33,26 +33,37 @@
         mWallpaperManager = WallpaperManager.getInstance(mContext);
     }
 
+    /**
+     * Suggesting desired dimensions is only a hint to the system that can be ignored.
+     *
+     * Test if the desired minimum width or height the WallpaperManager returns
+     * is greater than 0. If so, then we check whether that the size is at least the
+     * as big as the screen.
+     */
     public void testSuggestDesiredDimensions() {
-        Point min = getScreenSize();
-        int w = min.x * 3;
-        int h = min.y * 2;
+        final Point min = getScreenSize();
+        final int w = min.x * 3;
+        final int h = min.y * 2;
 
-        mWallpaperManager.suggestDesiredDimensions(min.x / 2, min.y / 2);
-        assertEquals(min.x, mWallpaperManager.getDesiredMinimumWidth());
-        assertEquals(min.y, mWallpaperManager.getDesiredMinimumHeight());
+        assertDesiredMinimum(new Point(min.x / 2, min.y / 2), min);
 
-        mWallpaperManager.suggestDesiredDimensions(w, h);
-        assertEquals(w, mWallpaperManager.getDesiredMinimumWidth());
-        assertEquals(h, mWallpaperManager.getDesiredMinimumHeight());
+        assertDesiredMinimum(new Point(w, h),
+                             new Point(w, h));
 
-        mWallpaperManager.suggestDesiredDimensions(min.x / 2, h);
-        assertEquals(min.x, mWallpaperManager.getDesiredMinimumWidth());
-        assertEquals(h, mWallpaperManager.getDesiredMinimumHeight());
+        assertDesiredMinimum(new Point(min.x / 2, h),
+                             new Point(min.x, h));
 
-        mWallpaperManager.suggestDesiredDimensions(w, min.y / 2);
-        assertEquals(w, mWallpaperManager.getDesiredMinimumWidth());
-        assertEquals(min.y, mWallpaperManager.getDesiredMinimumHeight());
+        assertDesiredMinimum(new Point(w, min.y / 2),
+                             new Point(w, min.y));
+    }
+
+    private void assertDesiredMinimum(Point suggestedSize, Point expectedSize) {
+        mWallpaperManager.suggestDesiredDimensions(suggestedSize.x, suggestedSize.y);
+        Point actualSize = new Point(mWallpaperManager.getDesiredMinimumWidth(),
+                mWallpaperManager.getDesiredMinimumHeight());
+        if (actualSize.x > 0 || actualSize.y > 0) {
+            assertEquals(expectedSize, actualSize);
+        }
     }
 
     private Point getScreenSize() {
diff --git a/tests/tests/content/src/android/content/pm/cts/ResolveInfo_DisplayNameComparatorTest.java b/tests/tests/content/src/android/content/pm/cts/ResolveInfo_DisplayNameComparatorTest.java
deleted file mode 100644
index be3d99c..0000000
--- a/tests/tests/content/src/android/content/pm/cts/ResolveInfo_DisplayNameComparatorTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm.cts;
-
-
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ResolveInfo.DisplayNameComparator;
-import android.test.AndroidTestCase;
-
-public class ResolveInfo_DisplayNameComparatorTest extends AndroidTestCase {
-    private static final String MAIN_ACTION_NAME = "android.intent.action.MAIN";
-    private static final String SERVICE_NAME = "android.content.pm.cts.activity.PMTEST_SERVICE";
-
-    public void testDisplayNameComparator() {
-        PackageManager pm = getContext().getPackageManager();
-        DisplayNameComparator dnc = new DisplayNameComparator(pm);
-
-        Intent intent = new Intent(MAIN_ACTION_NAME);
-        ResolveInfo activityInfo = pm.resolveActivity(intent, 0);
-
-        intent = new Intent(SERVICE_NAME);
-        ResolveInfo serviceInfo = pm.resolveService(intent, PackageManager.GET_RESOLVED_FILTER);
-
-        assertTrue(dnc.compare(activityInfo, serviceInfo) < 0);
-        assertTrue(dnc.compare(activityInfo, activityInfo) == 0);
-        assertTrue(dnc.compare(serviceInfo, activityInfo) > 0);
-    }
-}
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
index 4ecabc5..e2f75c6 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
@@ -17,6 +17,7 @@
 package android.dpi.cts;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
 import android.util.DisplayMetrics;
 import android.view.Display;
@@ -40,8 +41,13 @@
         double xInches = (double) metrics.widthPixels / metrics.xdpi;
         double yInches = (double) metrics.heightPixels / metrics.ydpi;
         double diagonalInches = Math.sqrt(Math.pow(xInches, 2) + Math.pow(yInches, 2));
-        assertTrue("Screen diagonal must be at least 2.5 inches: " + diagonalInches,
-                diagonalInches >= 2.5d);
+        double minSize = 2.5d;
+        if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            // Watches have a different minimum diagonal.
+            minSize = 1.0d;
+        }
+        assertTrue("Screen diagonal must be at least " + minSize + " inches: " + diagonalInches,
+                diagonalInches >= minSize);
 
         double density = 160.0d * metrics.density;
         assertTrue("Screen density must be at least 100 dpi: " + density, density >= 100.0d);
diff --git a/tests/tests/drm/src/android/drm/cts/DRMTest.java b/tests/tests/drm/src/android/drm/cts/DRMTest.java
index bb77668..bd4291d 100644
--- a/tests/tests/drm/src/android/drm/cts/DRMTest.java
+++ b/tests/tests/drm/src/android/drm/cts/DRMTest.java
@@ -18,6 +18,7 @@
 
 
 import android.content.ContentValues;
+import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import java.io.IOException;
@@ -48,22 +49,30 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mDrmManagerClient = new DrmManagerClient(getContext());
-        String[] plugins = mDrmManagerClient.getAvailableDrmEngines();
 
-        mConfigs.clear();
-        for(String plugInName : plugins) {
-            Config config = ConfigFactory.getConfig(plugInName);
-            if (null != config) {
-                mConfigs.add(config);
+        if (deviceSupportsDRM()) {
+            mDrmManagerClient = new DrmManagerClient(getContext());
+            String[] plugins = mDrmManagerClient.getAvailableDrmEngines();
+
+            mConfigs.clear();
+            for(String plugInName : plugins) {
+                Config config = ConfigFactory.getConfig(plugInName);
+                if (null != config) {
+                    mConfigs.add(config);
+                }
             }
         }
     }
 
+    private boolean deviceSupportsDRM() {
+       /* Watches don't support DRM */
+        return !getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+    }
+
     private void register(Config config) throws Exception {
         DrmInfo drmInfo = executeAcquireDrmInfo(DrmInfoRequest.TYPE_REGISTRATION_INFO,
-                                            config.getInfoOfRegistration(),
-                                            config.getMimeType());
+                config.getInfoOfRegistration(),
+                config.getMimeType());
         executeProcessDrmInfo(drmInfo, config);
     }
 
@@ -82,86 +91,106 @@
     }
 
     public void testIsDrmDirectoryExist() {
-        assertTrue("/data/drm/ does not exist", new File("/data/drm/").exists());
+        if (deviceSupportsDRM()) {
+            assertTrue("/data/drm/ does not exist", new File("/data/drm/").exists());
+        }
     }
 
     public void testRegisterAndDeregister() throws Exception {
-        for (Config config : mConfigs) {
-            register(config);
-            deregister(config);
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                register(config);
+                deregister(config);
+            }
         }
     }
 
     public void testAcquireRights() throws Exception {
-        for (Config config : mConfigs) {
-            register(config);
-            acquireRights(config);
-            deregister(config);
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                register(config);
+                acquireRights(config);
+                deregister(config);
+            }
         }
     }
 
     public void testGetConstraints() throws Exception {
-        for (Config config : mConfigs) {
-            register(config);
-            acquireRights(config);
-            ContentValues constraints = mDrmManagerClient.getConstraints(
-                                            config.getContentPath(),
-                                            DrmStore.Action.DEFAULT);
-            assertNotNull("Failed on plugin: " + config.getPluginName(), constraints);
-            deregister(config);
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                register(config);
+                acquireRights(config);
+                ContentValues constraints = mDrmManagerClient.getConstraints(
+                                                                             config.getContentPath(),
+                                                                             DrmStore.Action.DEFAULT);
+                assertNotNull("Failed on plugin: " + config.getPluginName(), constraints);
+                deregister(config);
+            }
         }
     }
 
     public void testCanHandle() throws Exception {
-        for (Config config : mConfigs) {
-            assertTrue("Failed on plugin: " + config.getPluginName(),
-                    mDrmManagerClient.canHandle(config.getContentPath(), config.getMimeType()));
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                assertTrue("Failed on plugin: " + config.getPluginName(),
+                        mDrmManagerClient.canHandle(config.getContentPath(), config.getMimeType()));
+            }
         }
     }
 
     public void testGetOriginalMimeType() throws Exception {
-        for (Config config : mConfigs) {
-            assertNotNull("Failed on plugin: " + config.getPluginName(),
-                    mDrmManagerClient.getOriginalMimeType(config.getContentPath()));
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                assertNotNull("Failed on plugin: " + config.getPluginName(),
+                        mDrmManagerClient.getOriginalMimeType(config.getContentPath()));
+            }
         }
     }
 
     public void testCheckRightsStatus() throws Exception {
-        for (Config config : mConfigs) {
-            register(config);
-            acquireRights(config);
-            int rightsStatus = mDrmManagerClient.checkRightsStatus(
-                                                config.getContentPath(),
-                                                DrmStore.Action.PLAY);
-            assertEquals("Failed on plugin: " + config.getPluginName(),
-                    DrmStore.RightsStatus.RIGHTS_VALID, rightsStatus);
-            deregister(config);
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                register(config);
+                acquireRights(config);
+                int rightsStatus = mDrmManagerClient.checkRightsStatus(
+                                                                       config.getContentPath(),
+                                                                       DrmStore.Action.PLAY);
+                assertEquals("Failed on plugin: " + config.getPluginName(),
+                        DrmStore.RightsStatus.RIGHTS_VALID, rightsStatus);
+                deregister(config);
+            }
         }
     }
 
     public void testRemoveRights() throws Exception {
-        for (Config config : mConfigs) {
-            assertEquals("Failed on plugin: " + config.getPluginName(),
-                    DrmManagerClient.ERROR_NONE,
-                    mDrmManagerClient.removeRights(config.getContentPath()));
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                assertEquals("Failed on plugin: " + config.getPluginName(),
+                        DrmManagerClient.ERROR_NONE,
+                        mDrmManagerClient.removeRights(config.getContentPath()));
+            }
         }
     }
 
     public void testRemoveAllRights() throws Exception {
-        for (Config config : mConfigs) {
-            assertEquals("Failed on plugin: " + config.getPluginName(),
-                    mDrmManagerClient.removeAllRights(), DrmManagerClient.ERROR_NONE);
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                assertEquals("Failed on plugin: " + config.getPluginName(),
+                        mDrmManagerClient.removeAllRights(), DrmManagerClient.ERROR_NONE);
+            }
         }
     }
 
     public void testConvertData() throws Exception {
-        for (Config config : mConfigs) {
-            byte[] inputData = new byte[]{'T','E','S','T'};
+        if (deviceSupportsDRM()) {
+            for (Config config : mConfigs) {
+                byte[] inputData = new byte[]{'T','E','S','T'};
 
-            int convertId = mDrmManagerClient.openConvertSession(config.getMimeType());
-            DrmConvertedStatus drmConvertStatus
-                                = mDrmManagerClient.convertData(convertId, inputData);
-            mDrmManagerClient.closeConvertSession(convertId);
+                int convertId = mDrmManagerClient.openConvertSession(config.getMimeType());
+                DrmConvertedStatus drmConvertStatus
+                    = mDrmManagerClient.convertData(convertId, inputData);
+                mDrmManagerClient.closeConvertSession(convertId);
+            }
         }
     }
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintFlagsDrawFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintFlagsDrawFilterTest.java
index 31dbf16..ee3ec7c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintFlagsDrawFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintFlagsDrawFilterTest.java
@@ -107,4 +107,82 @@
         // underline is under the text or at least at the bottom of it
         assertTrue(rect.top >= TEXT_Y);
     }
+
+    // Tests that FILTER_BITMAP_FLAG is handled properly.
+    public void testPaintFlagsDrawFilter2() {
+        // Create a bitmap with alternating black and white pixels.
+        int kWidth = 5;
+        int kHeight = 5;
+        int colors[] = new int [] { Color.WHITE, Color.BLACK };
+        int k = 0;
+        Bitmap grid = Bitmap.createBitmap(kWidth, kHeight, Config.ARGB_8888);
+        for (int i = 0; i < kWidth; ++i) {
+            for (int j = 0; j < kHeight; ++j) {
+                grid.setPixel(i, j, colors[k]);
+                k = (k + 1) % 2;
+            }
+        }
+
+        // Setup a scaled canvas for drawing the bitmap, with and without FILTER_BITMAP_FLAG set.
+        // When the flag is set, there will be gray pixels. When the flag is not set, all pixels
+        // will be either black or white.
+        int kScale = 5;
+        Bitmap dst = Bitmap.createBitmap(kWidth * kScale, kHeight * kScale, Config.ARGB_8888);
+        Canvas canvas = new Canvas(dst);
+        canvas.scale(kScale, kScale);
+
+        // Drawn without FILTER_BITMAP_FLAG, all pixels will be black or white.
+        Paint simplePaint = new Paint();
+        canvas.drawBitmap(grid, 0, 0, simplePaint);
+
+        assertContainsOnlyBlackAndWhite(dst);
+
+        // Drawn with FILTER_BITMAP_FLAG, some pixels will be somewhere in between.
+        Paint filterBitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+        canvas.drawBitmap(grid, 0, 0, filterBitmapPaint);
+
+        assertContainsNonBW(dst);
+
+        // Drawing with a paint that FILTER_BITMAP_FLAG set and a DrawFilter that removes
+        // FILTER_BITMAP_FLAG should remove the effect of the flag, resulting in all pixels being
+        // either black or white.
+        canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
+        canvas.drawBitmap(grid, 0, 0, filterBitmapPaint);
+
+        assertContainsOnlyBlackAndWhite(dst);
+
+        // Likewise, drawing with a DrawFilter that sets FILTER_BITMAP_FLAG should filter,
+        // resulting in gray pixels.
+        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
+        canvas.drawBitmap(grid, 0, 0, simplePaint);
+
+        assertContainsNonBW(dst);
+    }
+
+    // Assert that at least one pixel is neither black nor white. This is used to verify that
+    // filtering was done, since the original bitmap only contained black and white pixels.
+    private void assertContainsNonBW(Bitmap bitmap) {
+        for (int i = 0; i < bitmap.getWidth(); ++i) {
+            for (int j = 0; j < bitmap.getHeight(); ++j) {
+                int color = bitmap.getPixel(i, j);
+                if (color != Color.BLACK && color != Color.WHITE) {
+                    // Filtering must have been done.
+                    return;
+                }
+            }
+        }
+        // Filtering did not happen.
+        assertTrue(false);
+    }
+
+    // Assert that every pixel is either black or white. Used to verify that no filtering was
+    // done, since the original bitmap contained only black and white pixels.
+    private void assertContainsOnlyBlackAndWhite(Bitmap bitmap) {
+        for (int i = 0; i < bitmap.getWidth(); ++i) {
+            for (int j = 0; j < bitmap.getHeight(); ++j) {
+                int color = bitmap.getPixel(i, j);
+                assertTrue(color == Color.BLACK || color == Color.WHITE);
+            }
+        }
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
index c8a5e24..2cba287 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
@@ -27,7 +27,7 @@
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.NinePatchDrawable;
-import android.graphics.drawable.TouchFeedbackDrawable;
+import android.graphics.drawable.RippleDrawable;
 import android.test.AndroidTestCase;
 import android.util.SparseIntArray;
 import android.view.ContextThemeWrapper;
@@ -126,11 +126,11 @@
         // assertNotNull(d.getNinePatch());
     }
 
-    public void testTouchFeedbackDrawable() {
-        TouchFeedbackDrawable d = (TouchFeedbackDrawable) mContext.getDrawable(
-                R.drawable.touchfeedbackdrawable_theme);
+    public void testRippleDrawable() {
+        RippleDrawable d = (RippleDrawable) mContext.getDrawable(
+                R.drawable.rippledrawable_theme);
 
-        // assertEquals(Color.BLACK, d.getPressColor());
+        // assertEquals(Color.BLACK, d.getTint());
     }
     
     public void testLayerDrawable() {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
index b27e0d6..f09b1f1 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
@@ -32,8 +32,8 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.Size;
+import android.hardware.camera2.TotalCaptureResult;
+import android.util.Size;
 import android.hardware.camera2.cts.helpers.MaybeNull;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.rs.RenderScriptSingleton;
@@ -48,6 +48,7 @@
 import android.renderscript.Script.LaunchOptions;
 import android.test.AndroidTestCase;
 import android.util.Log;
+import android.util.Rational;
 import android.view.Surface;
 
 import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
@@ -378,7 +379,7 @@
         mCamera.capture(request, new CameraDevice.CaptureListener() {
             @Override
             public void onCaptureCompleted(CameraDevice camera, CaptureRequest request,
-                    CaptureResult result) {
+                    TotalCaptureResult result) {
                 if (VERBOSE) Log.v(TAG, "Capture completed");
             }
         }, mHandler);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java
index b1639da..ac5c889 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java
@@ -27,7 +27,7 @@
 import android.content.Context;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraMetadata.Key;
+import android.hardware.camera2.CameraCharacteristics.Key;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -751,75 +751,6 @@
         }
     }
 
-    public void testCameraCharacteristicsAndroidScalerAvailableFormats() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            {
-
-                assertNotNull("Invalid property: android.scaler.availableFormats",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableFormats", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
-
-            }
-
-        }
-    }
-
-    public void testCameraCharacteristicsAndroidScalerAvailableJpegMinDurations() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            {
-
-                assertNotNull("Invalid property: android.scaler.availableJpegMinDurations",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_JPEG_MIN_DURATIONS));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableJpegMinDurations", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_JPEG_MIN_DURATIONS));
-
-            }
-
-        }
-    }
-
-    public void testCameraCharacteristicsAndroidScalerAvailableJpegSizes() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            {
-
-                assertNotNull("Invalid property: android.scaler.availableJpegSizes",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_JPEG_SIZES));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableJpegSizes", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_JPEG_SIZES));
-
-            }
-
-        }
-    }
-
     public void testCameraCharacteristicsAndroidScalerAvailableMaxDigitalZoom() throws Exception {
         String[] ids = mCameraManager.getCameraIdList();
         for (int i = 0; i < ids.length; i++) {
@@ -843,7 +774,7 @@
         }
     }
 
-    public void testCameraCharacteristicsAndroidScalerAvailableProcessedMinDurations() throws Exception {
+    public void testCameraCharacteristicsAndroidScalerStreamConfigurationMap() throws Exception {
         String[] ids = mCameraManager.getCameraIdList();
         for (int i = 0; i < ids.length; i++) {
             CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
@@ -852,21 +783,21 @@
 
             {
 
-                assertNotNull("Invalid property: android.scaler.availableProcessedMinDurations",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS));
+                assertNotNull("Invalid property: android.scaler.streamConfigurationMap",
+                        props.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP));
 
                 List<Key<?>> allKeys = props.getKeys();
                 assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
                         ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableProcessedMinDurations", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS));
+                assertTrue("Key not in keys list: android.scaler.streamConfigurationMap", allKeys.contains(
+                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP));
 
             }
 
         }
     }
 
-    public void testCameraCharacteristicsAndroidScalerAvailableProcessedSizes() throws Exception {
+    public void testCameraCharacteristicsAndroidScalerCroppingType() throws Exception {
         String[] ids = mCameraManager.getCameraIdList();
         for (int i = 0; i < ids.length; i++) {
             CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
@@ -875,106 +806,14 @@
 
             {
 
-                assertNotNull("Invalid property: android.scaler.availableProcessedSizes",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_PROCESSED_SIZES));
+                assertNotNull("Invalid property: android.scaler.croppingType",
+                        props.get(CameraCharacteristics.SCALER_CROPPING_TYPE));
 
                 List<Key<?>> allKeys = props.getKeys();
                 assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
                         ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableProcessedSizes", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_PROCESSED_SIZES));
-
-            }
-
-        }
-    }
-
-    public void testCameraCharacteristicsAndroidScalerAvailableInputOutputFormatsMap() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            {
-
-                assertNotNull("Invalid property: android.scaler.availableInputOutputFormatsMap",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableInputOutputFormatsMap", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP));
-
-            }
-
-        }
-    }
-
-    public void testCameraCharacteristicsAndroidScalerAvailableStreamConfigurations() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            {
-
-                assertNotNull("Invalid property: android.scaler.availableStreamConfigurations",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableStreamConfigurations", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS));
-
-            }
-
-        }
-    }
-
-    public void testCameraCharacteristicsAndroidScalerAvailableMinFrameDurations() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            {
-
-                assertNotNull("Invalid property: android.scaler.availableMinFrameDurations",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableMinFrameDurations", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS));
-
-            }
-
-        }
-    }
-
-    public void testCameraCharacteristicsAndroidScalerAvailableStallDurations() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            {
-
-                assertNotNull("Invalid property: android.scaler.availableStallDurations",
-                        props.get(CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.scaler.availableStallDurations", allKeys.contains(
-                        CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS));
+                assertTrue("Key not in keys list: android.scaler.croppingType", allKeys.contains(
+                        CameraCharacteristics.SCALER_CROPPING_TYPE));
 
             }
 
@@ -1189,33 +1028,6 @@
         }
     }
 
-    public void testCameraCharacteristicsAndroidSensorBaseGainFactor() throws Exception {
-        String[] ids = mCameraManager.getCameraIdList();
-        for (int i = 0; i < ids.length; i++) {
-            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
-            assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
-                                        props);
-
-            Integer hwLevel = props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
-            assertNotNull("No hardware level reported! android.info.supportedHardwareLevel",
-                    hwLevel);
-            if (hwLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
-            {
-
-                assertNotNull("Invalid property: android.sensor.baseGainFactor",
-                        props.get(CameraCharacteristics.SENSOR_BASE_GAIN_FACTOR));
-
-                List<Key<?>> allKeys = props.getKeys();
-                assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
-                        ids[i], props));
-                assertTrue("Key not in keys list: android.sensor.baseGainFactor", allKeys.contains(
-                        CameraCharacteristics.SENSOR_BASE_GAIN_FACTOR));
-
-            }
-
-        }
-    }
-
     public void testCameraCharacteristicsAndroidSensorBlackLevelPattern() throws Exception {
         String[] ids = mCameraManager.getCameraIdList();
         for (int i = 0; i < ids.length; i++) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 55cd5d2..d7cacd3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -19,17 +19,16 @@
 import static android.hardware.camera2.cts.CameraTestUtils.*;
 import static com.android.ex.camera2.blocking.BlockingStateListener.*;
 import static org.mockito.Mockito.*;
-import static android.hardware.camera2.CameraMetadata.*;
 import static android.hardware.camera2.CaptureRequest.*;
 
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
 import android.os.SystemClock;
 import android.util.Log;
@@ -439,15 +438,15 @@
         }
     }
 
-    private class IsCameraMetadataNotEmpty<T extends CameraMetadata>
-            extends ArgumentMatcher<T> {
+    private class IsCaptureResultNotEmpty
+            extends ArgumentMatcher<TotalCaptureResult> {
         @Override
         public boolean matches(Object obj) {
             /**
              * Do the simple verification here. Only verify the timestamp for now.
              * TODO: verify more required capture result metadata fields.
              */
-            CameraMetadata result = (CameraMetadata) obj;
+            TotalCaptureResult result = (TotalCaptureResult) obj;
             Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
             if (timeStamp != null && timeStamp.longValue() > 0L) {
                 return true;
@@ -621,12 +620,12 @@
                         .onCaptureCompleted(
                                 eq(mCamera),
                                 isA(CaptureRequest.class),
-                                argThat(new IsCameraMetadataNotEmpty<CaptureResult>()));
+                                argThat(new IsCaptureResultNotEmpty()));
         // Should not receive any capture failed callbacks.
         verify(mockListener, never())
                         .onCaptureFailed(
                                 eq(mCamera),
-                                argThat(new IsCameraMetadataNotEmpty<CaptureRequest>()),
+                                isA(CaptureRequest.class),
                                 isA(CaptureFailure.class));
         // Should receive expected number of capture shutter calls
         verify(mockListener,
@@ -640,7 +639,7 @@
 
     private void checkFpsRange(CaptureRequest.Builder request, int template,
             CameraCharacteristics props) {
-        Key<int[]> fpsRangeKey = CONTROL_AE_TARGET_FPS_RANGE;
+        CaptureRequest.Key<int[]> fpsRangeKey = CONTROL_AE_TARGET_FPS_RANGE;
         int[] fpsRange;
         if ((fpsRange = mCollector.expectKeyValueNotNull(request, fpsRangeKey)) == null) {
             return;
@@ -700,15 +699,15 @@
             return;
         }
 
-        int targetAfMode = CONTROL_AF_MODE_AUTO;
+        int targetAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO;
         byte[] availableAfMode = props.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
         if (template == CameraDevice.TEMPLATE_PREVIEW ||
                 template == CameraDevice.TEMPLATE_STILL_CAPTURE ||
                 template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG) {
             // Default to CONTINUOUS_PICTURE if it is available, otherwise AUTO.
             for (int i = 0; i < availableAfMode.length; i++) {
-                if (availableAfMode[i] == CONTROL_AF_MODE_CONTINUOUS_PICTURE) {
-                    targetAfMode = CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+                if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) {
+                    targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
                     break;
                 }
             }
@@ -716,13 +715,13 @@
                 template == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
             // Default to CONTINUOUS_VIDEO if it is available, otherwise AUTO.
             for (int i = 0; i < availableAfMode.length; i++) {
-                if (availableAfMode[i] == CONTROL_AF_MODE_CONTINUOUS_VIDEO) {
-                    targetAfMode = CONTROL_AF_MODE_CONTINUOUS_VIDEO;
+                if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) {
+                    targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
                     break;
                 }
             }
         } else if (template == CameraDevice.TEMPLATE_MANUAL) {
-            targetAfMode = CONTROL_AF_MODE_OFF;
+            targetAfMode = CaptureRequest.CONTROL_AF_MODE_OFF;
         }
 
         mCollector.expectKeyValueEquals(request, CONTROL_AF_MODE, targetAfMode);
@@ -743,7 +742,8 @@
             CameraCharacteristics props) {
         // 3A settings--control.mode.
         if (template != CameraDevice.TEMPLATE_MANUAL) {
-            mCollector.expectKeyValueEquals(request, CONTROL_MODE, CONTROL_MODE_AUTO);
+            mCollector
+                    .expectKeyValueEquals(request, CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
         }
 
         // 3A settings--AE/AWB/AF.
@@ -751,22 +751,27 @@
         checkAfMode(request, template, props);
         checkFpsRange(request, template, props);
         if (template == CameraDevice.TEMPLATE_MANUAL) {
-            mCollector.expectKeyValueEquals(request, CONTROL_MODE, CONTROL_MODE_OFF);
-            mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE, CONTROL_AE_MODE_OFF);
-            mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE, CONTROL_AWB_MODE_OFF);
+            mCollector.expectKeyValueEquals(request, CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
+            mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
+                    CaptureRequest.CONTROL_AE_MODE_OFF);
+            mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
+                    CaptureRequest.CONTROL_AWB_MODE_OFF);
 
         } else {
-            mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
+            mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
+                    CaptureRequest.CONTROL_AE_MODE_ON);
             mCollector.expectKeyValueNotEquals(request, CONTROL_AE_ANTIBANDING_MODE,
-                    CONTROL_AE_ANTIBANDING_MODE_OFF);
+                    CaptureRequest.CONTROL_AE_ANTIBANDING_MODE_OFF);
             mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0);
             mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
             mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER,
-                    CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
+                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
 
-            mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_IDLE);
+            mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER,
+                    CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
 
-            mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE, CONTROL_AWB_MODE_AUTO);
+            mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
+                    CaptureRequest.CONTROL_AWB_MODE_AUTO);
             mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
 
             // Check 3A regions.
@@ -816,51 +821,61 @@
 
         // ISP-processing settings.
         mCollector.expectKeyValueEquals(
-                request, STATISTICS_FACE_DETECT_MODE, STATISTICS_FACE_DETECT_MODE_OFF);
-        mCollector.expectKeyValueEquals(request, FLASH_MODE, FLASH_MODE_OFF);
+                request, STATISTICS_FACE_DETECT_MODE,
+                CaptureRequest.STATISTICS_FACE_DETECT_MODE_OFF);
+        mCollector.expectKeyValueEquals(request, FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
         mCollector.expectKeyValueEquals(
-                request, STATISTICS_LENS_SHADING_MAP_MODE, STATISTICS_LENS_SHADING_MAP_MODE_OFF);
+                request, STATISTICS_LENS_SHADING_MAP_MODE,
+                CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_OFF);
 
         if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) {
             // Not enforce high quality here, as some devices may not effectively have high quality
             // mode.
             mCollector.expectKeyValueNotEquals(
-                    request, COLOR_CORRECTION_MODE, COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
+                    request, COLOR_CORRECTION_MODE,
+                    CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
 
             List<Byte> availableEdgeModes =
                     Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
-            if (availableEdgeModes.contains((byte)EDGE_MODE_HIGH_QUALITY)) {
-                mCollector.expectKeyValueEquals(request, EDGE_MODE, EDGE_MODE_HIGH_QUALITY);
-            } else if (availableEdgeModes.contains((byte)EDGE_MODE_FAST)) {
-                mCollector.expectKeyValueEquals(request, EDGE_MODE, EDGE_MODE_FAST);
+            if (availableEdgeModes.contains((byte) CaptureRequest.EDGE_MODE_HIGH_QUALITY)) {
+                mCollector.expectKeyValueEquals(request, EDGE_MODE,
+                        CaptureRequest.EDGE_MODE_HIGH_QUALITY);
+            } else if (availableEdgeModes.contains((byte) CaptureRequest.EDGE_MODE_FAST)) {
+                mCollector.expectKeyValueEquals(request, EDGE_MODE, CaptureRequest.EDGE_MODE_FAST);
             } else {
-                mCollector.expectKeyValueEquals(request, EDGE_MODE, EDGE_MODE_OFF);
+                mCollector.expectKeyValueEquals(request, EDGE_MODE, CaptureRequest.EDGE_MODE_OFF);
             }
 
             List<Byte> availableNoiseReductionModes =
                     Arrays.asList(toObject(mStaticInfo.getAvailableNoiseReductionModesChecked()));
-            if (availableNoiseReductionModes.contains((byte)NOISE_REDUCTION_MODE_HIGH_QUALITY)) {
+            if (availableNoiseReductionModes
+                    .contains((byte) CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY)) {
                 mCollector.expectKeyValueEquals(
-                        request, NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODE_HIGH_QUALITY);
-            } else if (availableNoiseReductionModes.contains((byte)NOISE_REDUCTION_MODE_FAST)) {
+                        request, NOISE_REDUCTION_MODE,
+                        CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
+            } else if (availableNoiseReductionModes
+                    .contains((byte) CaptureRequest.NOISE_REDUCTION_MODE_FAST)) {
                 mCollector.expectKeyValueEquals(
-                        request, NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODE_FAST);
+                        request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_FAST);
             } else {
                 mCollector.expectKeyValueEquals(
-                        request, NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODE_OFF);
+                        request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
             }
 
             List<Byte> availableToneMapModes =
                     Arrays.asList(toObject(mStaticInfo.getAvailableToneMapModesChecked()));
-            if (availableToneMapModes.contains((byte)TONEMAP_MODE_HIGH_QUALITY)) {
-                mCollector.expectKeyValueEquals(request, TONEMAP_MODE, TONEMAP_MODE_HIGH_QUALITY);
+            if (availableToneMapModes.contains((byte) CaptureRequest.TONEMAP_MODE_HIGH_QUALITY)) {
+                mCollector.expectKeyValueEquals(request, TONEMAP_MODE,
+                        CaptureRequest.TONEMAP_MODE_HIGH_QUALITY);
             } else {
-                mCollector.expectKeyValueEquals(request, TONEMAP_MODE, TONEMAP_MODE_FAST);
+                mCollector.expectKeyValueEquals(request, TONEMAP_MODE,
+                        CaptureRequest.TONEMAP_MODE_FAST);
             }
         } else {
             mCollector.expectKeyValueNotNull(request, EDGE_MODE);
             mCollector.expectKeyValueNotNull(request, NOISE_REDUCTION_MODE);
-            mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE, TONEMAP_MODE_CONTRAST_CURVE);
+            mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE,
+                    CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE);
         }
 
         mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, template);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index 14860b6..e157b4c 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -25,13 +25,13 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Size;
-import android.hardware.camera2.CameraMetadata.Key;
+import android.hardware.camera2.TotalCaptureResult;
+import android.util.Size;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
 import android.media.ImageReader;
 import android.media.Image.Plane;
@@ -140,7 +140,7 @@
 
         @Override
         public void onCaptureCompleted(CameraDevice camera, CaptureRequest request,
-                CaptureResult result) {
+                TotalCaptureResult result) {
             try {
                 mQueue.put(result);
             } catch (InterruptedException e) {
@@ -156,7 +156,7 @@
 
         @Override
         public void onCaptureSequenceCompleted(CameraDevice camera, int sequenceId,
-                int frameNumber) {
+                long frameNumber) {
         }
 
         public CaptureResult getCaptureResult(long timeout) {
@@ -423,28 +423,21 @@
         }
     }
 
+    /**
+     * Get the available output sizes for the user-defined {@code format}.
+     *
+     * <p>Note that implementation-defined/hidden formats are not supported.</p>
+     */
     public static Size[] getSupportedSizeForFormat(int format, String cameraId,
             CameraManager cameraManager) throws CameraAccessException {
-        CameraMetadata.Key<Size[]> key = null;
         CameraCharacteristics properties = cameraManager.getCameraCharacteristics(cameraId);
         assertNotNull("Can't get camera characteristics!", properties);
         if (VERBOSE) {
             Log.v(TAG, "get camera characteristics for camera: " + cameraId);
         }
-        switch (format) {
-            case ImageFormat.JPEG:
-                key = CameraCharacteristics.SCALER_AVAILABLE_JPEG_SIZES;
-                break;
-            case ImageFormat.YUV_420_888:
-            case ImageFormat.YV12:
-            case ImageFormat.NV21:
-                key = CameraCharacteristics.SCALER_AVAILABLE_PROCESSED_SIZES;
-                break;
-            default:
-                throw new UnsupportedOperationException(
-                        String.format("Invalid format specified 0x%x", format));
-        }
-        Size[] availableSizes = properties.get(key);
+        StreamConfigurationMap configMap =
+                properties.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+        Size[] availableSizes = configMap.getOutputSizes(format);
         assertArrayNotEmpty(availableSizes, "availableSizes should not be empty");
         if (VERBOSE) Log.v(TAG, "Supported sizes are: " + Arrays.deepToString(availableSizes));
         return availableSizes;
@@ -806,7 +799,7 @@
         return;
     }
 
-    public static <T> T getValueNotNull(CaptureResult result, Key<T> key) {
+    public static <T> T getValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
         if (result == null) {
             throw new IllegalArgumentException("Result must not be null");
         }
@@ -884,4 +877,25 @@
                 /*right*/ cropCenterX + cropWidth / 2 - 1,
                 /*bottom*/cropCenterY + cropHeight / 2 - 1);
     }
+
+    /**
+     * Calculate output 3A region from the intersection of input 3A region and cropped region.
+     *
+     * @param requestRegion The input 3A region [xmin, ymin, xmax, ymax, weight]
+     * @param cropRect The cropped region
+     * @return expected 3A region output in capture result
+     */
+    public static int[] getExpectedOutputRegion(int[] requestRegion, Rect cropRect){
+        Rect requestRect = new Rect(requestRegion[0], requestRegion[1],
+                requestRegion[2], requestRegion[3]);
+        Rect resultRect = new Rect();
+        assertTrue("Input 3A region must intersect cropped region",
+                    resultRect.setIntersect(requestRect, cropRect));
+        return new int[] {
+                resultRect.left,
+                resultRect.top,
+                resultRect.right,
+                resultRect.bottom,
+                requestRegion[4]};
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 838807d..add91a4 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -27,13 +27,12 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Face;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.Size;
-import android.hardware.camera2.CameraMetadata.Key;
 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureListener;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
+import android.hardware.camera2.params.Face;
 import android.util.Log;
+import android.util.Rational;
+import android.util.Size;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -90,6 +89,12 @@
     private final Rational ZERO_R = new Rational(0, 1);
     private final Rational ONE_R = new Rational(1, 1);
 
+    private final int NUM_ALGORITHMS = 3; // AE, AWB and AF
+    private final int INDEX_ALGORITHM_AE = 0;
+    private final int INDEX_ALGORITHM_AWB = 1;
+    private final int INDEX_ALGORITHM_AF = 2;
+    private final int LENGTH_ALGORITHM_REGION = 5;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -857,7 +862,7 @@
 
         for (int i = 0; i < numFramesVerified; i++) {
             CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
-            Long resultExpTime = result.get(CaptureRequest.SENSOR_EXPOSURE_TIME);
+            Long resultExpTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
             assertNotNull("Exposure time shouldn't be null", resultExpTime);
             Integer flicker = result.get(CaptureResult.STATISTICS_SCENE_FLICKER);
             // Scene flicker result should be always available.
@@ -1329,7 +1334,7 @@
         for (int i = 0; i < numFramesVerified; i++) {
             CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
             mCollector.expectEquals("Capture result tonemap mode should match request", tonemapMode,
-                    result.get(CaptureRequest.TONEMAP_MODE));
+                    result.get(CaptureResult.TONEMAP_MODE));
             float[] mapRed = result.get(CaptureResult.TONEMAP_CURVE_RED);
             float[] mapGreen = result.get(CaptureResult.TONEMAP_CURVE_GREEN);
             float[] mapBlue = result.get(CaptureResult.TONEMAP_CURVE_BLUE);
@@ -1455,8 +1460,8 @@
                     NUM_FRAMES_VERIFIED);
 
             // Verify AF can finish a scan for CONTROL_AF_MODE_CONTINUOUS_* modes
-            if ((int)mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE ||
-                    (int)mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) {
+            if (mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE ||
+                    mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) {
                 List<Integer> afStateList = new ArrayList<Integer>();
                 afStateList.add(CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED);
                 afStateList.add(CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED);
@@ -1492,9 +1497,9 @@
 
         for (int mode : opticalStabModes) {
             listener = new SimpleCaptureListener();
-            requestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, (int) mode);
+            requestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, mode);
             mCamera.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
-            verifyCaptureResultForKey(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE, (int)mode,
+            verifyCaptureResultForKey(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE, mode,
                     listener, NUM_FRAMES_VERIFIED);
         }
 
@@ -1511,26 +1516,43 @@
                 new PointF(0.75f, 0.75f), // bottom right corner zoom, minimal zoom: 2x
         };
         final float maxZoom = mStaticInfo.getAvailableMaxDigitalZoomChecked();
+        final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
+        Rect[] cropRegions = new Rect[ZOOM_STEPS];
+        int [][] expectRegions = new int[ZOOM_STEPS][];
         Size maxPreviewSize = mOrderedPreviewSizes.get(0);
         CaptureRequest.Builder requestBuilder =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
         SimpleCaptureListener listener = new SimpleCaptureListener();
         startPreview(requestBuilder, maxPreviewSize, listener);
         CaptureRequest[] requests = new CaptureRequest[ZOOM_STEPS];
-        Rect[] cropRegions = new Rect[ZOOM_STEPS];
+
+        // Set algorithm regions to full active region
+        // TODO: test more different 3A regions
+        final int[] algoDefaultRegion = new int[] {
+            0, // xmin
+            0, // ymin
+            activeArraySize.width() - 1,  // xmax
+            activeArraySize.height() - 1, // ymax
+            1, // weight
+        };
+
+        for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
+            update3aRegion(requestBuilder, algo,  algoDefaultRegion);
+        }
 
         for (PointF center : TEST_ZOOM_CENTERS) {
             for (int i = 0; i < ZOOM_STEPS; i++) {
                 float zoomFactor = (float) (1.0f + (maxZoom - 1.0) * i / ZOOM_STEPS);
-                cropRegions[i] = getCropRegionForZoom(zoomFactor, center,
-                        mStaticInfo.getAvailableMaxDigitalZoomChecked(),
-                        mStaticInfo.getActiveArraySizeChecked());
+                cropRegions[i] = getCropRegionForZoom(zoomFactor, center, maxZoom, activeArraySize);
                 if (VERBOSE) {
                     Log.v(TAG, "Testing Zoom for factor " + zoomFactor + " and center " +
                             center.toString() + " The cropRegion is " + cropRegions[i].toString());
                 }
                 requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegions[i]);
                 requests[i] = requestBuilder.build();
+                expectRegions[i] = getExpectedOutputRegion(
+                        /*requestRegion*/algoDefaultRegion,
+                        /*cropRect*/     cropRegions[i]);
                 mCamera.capture(requests[i], listener, mHandler);
             }
 
@@ -1540,6 +1562,10 @@
                  result = listener.getCaptureResultForRequest(
                          requests[i], NUM_RESULTS_WAIT_TIMEOUT);
                  Rect cropRegion = getValueNotNull(result, CaptureResult.SCALER_CROP_REGION);
+                 // Verify Output 3A region is intersection of input 3A region and crop region
+                 for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
+                     validate3aRegion(result,algo,  expectRegions[i]);
+                 }
                  mCollector.expectEquals(" Request and result crop region should match",
                          cropRegions[i], cropRegion);
             }
@@ -1628,16 +1654,6 @@
     }
 
     /**
-     * Enable exposure manual control and change sensitivity and
-     * clamp the value into the supported range.
-     *
-     * <p>The exposure time is set to default value.</p>
-     */
-    private void changeExposure(CaptureRequest.Builder requestBuilder, int sensitivity) {
-        changeExposure(requestBuilder, DEFAULT_EXP_TIME_NS, sensitivity);
-    }
-
-    /**
      * Get the exposure time array that contains multiple exposure time steps in
      * the exposure time range.
      */
@@ -1752,9 +1768,11 @@
         mCollector.expectTrue(String.format("Frame duration (%d) should be longer than exposure"
                 + " time (%d) for a given capture", frameDuration, expTime),
                 frameDuration >= expTime);
+
+        validatePipelineDepth(result);
     }
 
-    private <T> T getValueNotNull(CaptureResult result, Key<T> key) {
+    private <T> T getValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
         T value = result.get(key);
         assertNotNull("Value of Key " + key.getName() + " shouldn't be null", value);
         return value;
@@ -1768,10 +1786,11 @@
      * @param listener The capture listener to get capture results
      * @param numFramesVerified The number of capture results to be verified
      */
-    private <T> void verifyCaptureResultForKey(Key<T> key, T requestMode,
+    private <T> void verifyCaptureResultForKey(CaptureResult.Key<T> key, T requestMode,
             SimpleCaptureListener listener, int numFramesVerified) {
         for (int i = 0; i < numFramesVerified; i++) {
             CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+            validatePipelineDepth(result);
             T resultMode = getValueNotNull(result, key);
             if (VERBOSE) {
                 Log.v(TAG, "Expect value: " + requestMode.toString() + " result value: "
@@ -1802,6 +1821,7 @@
     private void verifyFpsNotSlowDown(CaptureRequest.Builder requestBuilder,
             int numFramesVerified)  throws Exception {
         int[] fpsRanges = mStaticInfo.getAeAvailableTargetFpsRangesChecked();
+        boolean antiBandingOffIsSupported = mStaticInfo.isAntiBandingOffModeSupported();
         final int FPS_RANGE_SIZE = 2;
         int[] fpsRange = new int[FPS_RANGE_SIZE];
         SimpleCaptureListener resultListener;
@@ -1822,6 +1842,19 @@
                         fpsRange[0], fpsRange[1], previewSz.toString()));
             }
             requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
+            // Turn off auto antibanding to avoid exposure time and frame duration interference
+            // from antibanding algorithm.
+            if (antiBandingOffIsSupported) {
+                requestBuilder.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
+                        CaptureRequest.CONTROL_AE_ANTIBANDING_MODE_OFF);
+            } else {
+                // The device doesn't implement the OFF mode, test continues. It need make sure
+                // that the antibanding algorithm doesn't slow down the fps.
+                Log.i(TAG, "OFF antibanding mode is not supported, the camera device output must" +
+                        " not slow down the frame rate regardless of its current antibanding" +
+                        " mode");
+            }
+
             resultListener = new SimpleCaptureListener();
             startPreview(requestBuilder, previewSz, resultListener);
             long[] frameDurationRange =
@@ -1829,6 +1862,7 @@
             for (int j = 0; j < numFramesVerified; j++) {
                 CaptureResult result =
                         resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+                validatePipelineDepth(result);
                 long frameDuration = getValueNotNull(result, CaptureResult.SENSOR_FRAME_DURATION);
                 mCollector.expectInRange(
                         "Frame duration must be in the range of " + Arrays.toString(frameDurationRange),
@@ -1842,6 +1876,20 @@
     }
 
     /**
+     * Validate the pipeline depth result.
+     *
+     * @param result The capture result to get pipeline depth data
+     */
+    private void validatePipelineDepth(CaptureResult result) {
+        final byte MIN_PIPELINE_DEPTH = 1;
+        byte maxPipelineDepth = mStaticInfo.getPipelineMaxDepthChecked();
+        Byte pipelineDepth = getValueNotNull(result, CaptureResult.REQUEST_PIPELINE_DEPTH);
+        mCollector.expectInRange(String.format("Pipeline depth must be in the range of [%d, %d]",
+                MIN_PIPELINE_DEPTH, maxPipelineDepth), pipelineDepth, MIN_PIPELINE_DEPTH,
+                maxPipelineDepth);
+    }
+
+    /**
      * Calculate the anti-flickering corrected exposure time.
      * <p>
      * If the input exposure time is very short (shorter than flickering
@@ -1875,4 +1923,78 @@
         correctedExpTime = correctedExpTime - (correctedExpTime % flickeringBoundary);
         return correctedExpTime;
     }
+
+    /**
+     * Update one 3A region in capture request builder if that region is supported. Do nothing
+     * if the specified 3A region is not supported by camera device.
+     * @param requestBuilder The request to be updated
+     * @param algoIdx The index to the algorithm. (AE: 0, AWB: 1, AF: 2)
+     * @param region The 3A region to be set
+     */
+    private void update3aRegion(CaptureRequest.Builder requestBuilder, int algoIdx, int[] region)
+    {
+        int[] maxRegions = mStaticInfo.get3aMaxRegionsChecked();
+
+        if (region.length == 0 ||
+                region.length % LENGTH_ALGORITHM_REGION != 0) {
+            throw new IllegalArgumentException("Invalid input 3A region!");
+        }
+
+        if (maxRegions[algoIdx] * LENGTH_ALGORITHM_REGION >= region.length)
+        {
+            switch (algoIdx) {
+                case INDEX_ALGORITHM_AE:
+                    requestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, region);
+                    break;
+                case INDEX_ALGORITHM_AWB:
+                    requestBuilder.set(CaptureRequest.CONTROL_AWB_REGIONS, region);
+                    break;
+                case INDEX_ALGORITHM_AF:
+                    requestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, region);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown 3A Algorithm!");
+            }
+        }
+    }
+
+    /**
+     * Validate one 3A region in capture result equals to expected region if that region is
+     * supported. Do nothing if the specified 3A region is not supported by camera device.
+     * @param result The capture result to be validated
+     * @param algoIdx The index to the algorithm. (AE: 0, AWB: 1, AF: 2)
+     * @param expectRegion The 3A region expected
+     */
+    private void validate3aRegion(CaptureResult result, int algoIdx, int[] expectRegion)
+    {
+        int[] maxRegions = mStaticInfo.get3aMaxRegionsChecked();
+        int[] actualRegion;
+
+        if (expectRegion.length == 0 ||
+                expectRegion.length % LENGTH_ALGORITHM_REGION != 0) {
+            throw new IllegalArgumentException("Invalid expected 3A region!");
+        }
+
+        if (maxRegions[algoIdx] > 0)
+        {
+            switch (algoIdx) {
+                case INDEX_ALGORITHM_AE:
+                    actualRegion = getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS);
+                    break;
+                case INDEX_ALGORITHM_AWB:
+                    actualRegion = getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS);
+                    break;
+                case INDEX_ALGORITHM_AF:
+                    actualRegion = getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown 3A Algorithm!");
+            }
+            mCollector.expectEquals(
+                    "Expected 3A region: " + Arrays.toString(expectRegion) +
+                    " does not match actual one: " + Arrays.toString(actualRegion),
+                    toObject(expectRegion),
+                    toObject(actualRegion));
+        }
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
index ffc263e..a66debe 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -22,7 +22,7 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
 
 import static android.hardware.camera2.cts.CameraTestUtils.*;
@@ -41,7 +41,7 @@
     private static final long WAIT_FOR_RESULT_TIMEOUT_MS = 3000;
 
     // List that includes all public keys from CaptureResult
-    List<CameraMetadata.Key<?>> mAllKeys;
+    List<CaptureResult.Key<?>> mAllKeys;
 
     // List tracking the failed test keys.
 
@@ -77,7 +77,7 @@
          * Hardcode a key waiver list for the keys that are allowed to be null.
          * FIXME: We need get ride of this list, see bug 11116270.
          */
-        List<CameraMetadata.Key<?>> waiverkeys = new ArrayList<CameraMetadata.Key<?>>();
+        List<CaptureResult.Key<?>> waiverkeys = new ArrayList<CaptureResult.Key<?>>();
         waiverkeys.add(CaptureResult.JPEG_GPS_COORDINATES);
         waiverkeys.add(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
         waiverkeys.add(CaptureResult.JPEG_GPS_TIMESTAMP);
@@ -85,7 +85,6 @@
         waiverkeys.add(CaptureResult.JPEG_QUALITY);
         waiverkeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY);
         waiverkeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE);
-        waiverkeys.add(CaptureResult.SENSOR_TEMPERATURE);
 
         for (String id : mCameraIds) {
             try {
@@ -145,13 +144,14 @@
     }
 
     private void validateCaptureResult(SimpleCaptureListener captureListener,
-            List<CameraMetadata.Key<?>> skippedKeys, CaptureRequest.Builder requestBuilder,
+            List<CaptureResult.Key<?>> skippedKeys, CaptureRequest.Builder requestBuilder,
             int numFramesVerified) throws Exception {
         CaptureResult result = null;
         for (int i = 0; i < numFramesVerified; i++) {
             String failMsg = "Failed capture result " + i + " test ";
             result = captureListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
-            for (CameraMetadata.Key<?> key : mAllKeys) {
+
+            for (CaptureResult.Key<?> key : mAllKeys) {
                 if (!skippedKeys.contains(key)) {
                     /**
                      * Check the critical tags here.
@@ -211,8 +211,8 @@
      * modify the comment blocks at the start or end.
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
 
-    private static List<CameraMetadata.Key<?>> getAllCaptureResultKeys() {
-        ArrayList<CameraMetadata.Key<?>> resultKeys = new ArrayList<CameraMetadata.Key<?>>();
+    private static List<CaptureResult.Key<?>> getAllCaptureResultKeys() {
+        ArrayList<CaptureResult.Key<?>> resultKeys = new ArrayList<CaptureResult.Key<?>>();
         resultKeys.add(CaptureResult.COLOR_CORRECTION_MODE);
         resultKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
         resultKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
@@ -263,7 +263,6 @@
         resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
         resultKeys.add(CaptureResult.SENSOR_SENSITIVITY);
         resultKeys.add(CaptureResult.SENSOR_TIMESTAMP);
-        resultKeys.add(CaptureResult.SENSOR_TEMPERATURE);
         resultKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
         resultKeys.add(CaptureResult.SENSOR_GREEN_SPLIT);
         resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA);
@@ -271,6 +270,7 @@
         resultKeys.add(CaptureResult.SHADING_MODE);
         resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
         resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
+        resultKeys.add(CaptureResult.STATISTICS_FACES);
         resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP);
         resultKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
         resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
@@ -281,10 +281,6 @@
         resultKeys.add(CaptureResult.TONEMAP_MODE);
         resultKeys.add(CaptureResult.BLACK_LEVEL_LOCK);
 
-        // Add STATISTICS_FACES key separately here because it is not
-        // defined in metadata xml file.
-        resultKeys.add(CaptureResult.STATISTICS_FACES);
-
         return resultKeys;
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 9939595..70fea4b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -24,7 +24,8 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Size;
+import android.util.Size;
+import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
 import android.media.Image;
 import android.media.ImageReader;
@@ -70,44 +71,69 @@
         super.tearDown();
     }
 
-    public void testImageReaderFromCameraFlexibleYuv() throws Exception {
-        for (int i = 0; i < mCameraIds.length; i++) {
-            try {
-                Log.i(TAG, "Testing Camera " + mCameraIds[i]);
-                openDevice(mCameraIds[i]);
-                bufferFormatTestByCamera(ImageFormat.YUV_420_888);
-            } finally {
-                closeDevice(mCameraIds[i]);
-            }
-        }
-    }
-
-    public void testImageReaderFromCameraJpeg() throws Exception {
-        for (int i = 0; i < mCameraIds.length; i++) {
-            try {
-                Log.v(TAG, "Testing Camera " + mCameraIds[i]);
-                openDevice(mCameraIds[i]);
-                bufferFormatTestByCamera(ImageFormat.JPEG);
-            } finally {
-                closeDevice(mCameraIds[i]);
-            }
-        }
-    }
-
-    public void testImageReaderFromCameraRaw() throws Exception {
+    public void testFlexibleYuv() throws Exception {
         for (String id : mCameraIds) {
             try {
-                Log.v(TAG, "Testing raw capture for camera " + id);
+                Log.i(TAG, "Testing Camera " + id);
                 openDevice(id);
-
-                bufferFormatTestByCamera(ImageFormat.RAW_SENSOR);
+                bufferFormatTestByCamera(ImageFormat.YUV_420_888, /*repeating*/true);
             } finally {
                 closeDevice(id);
             }
         }
     }
 
-    public void testImageReaderInvalidAccessTest() {
+    public void testJpeg() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing jpeg capture for Camera " + id);
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.JPEG, /*repeating*/false);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    public void testRaw() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing raw capture for camera " + id);
+                openDevice(id);
+
+                bufferFormatTestByCamera(ImageFormat.RAW_SENSOR, /*repeating*/false);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    public void testRepeatingJpeg() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing repeating jpeg capture for Camera " + id);
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.JPEG, /*repeating*/true);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    public void testRepeatingRaw() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing repeating raw capture for camera " + id);
+                openDevice(id);
+
+                bufferFormatTestByCamera(ImageFormat.RAW_SENSOR, /*repeating*/true);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    public void testInvalidAccessTest() {
         // TODO: test invalid access case, see if we can receive expected
         // exceptions
     }
@@ -117,7 +143,7 @@
      *
      * <p>Both stream formats are mandatory for Camera2 API</p>
      */
-    public void testImageReaderYuvAndJpeg() throws Exception {
+    public void testYuvAndJpeg() throws Exception {
         for (String id : mCameraIds) {
             try {
                 Log.v(TAG, "YUV and JPEG testing for camera " + id);
@@ -164,7 +190,7 @@
         final int NUM_SINGLE_CAPTURE_TESTED = MAX_NUM_IMAGES - 1;
         Size maxYuvSz = mOrderedPreviewSizes.get(0);
         Size[] targetCaptureSizes = mStaticInfo.getAvailableSizesForFormatChecked(format,
-                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+                StaticMetadata.StreamDirection.Output);
 
         for (Size captureSz : targetCaptureSizes) {
             if (VERBOSE) {
@@ -233,10 +259,10 @@
         }
     }
 
-    private void bufferFormatTestByCamera(int format) throws Exception {
+    private void bufferFormatTestByCamera(int format, boolean repeating) throws Exception {
 
         Size[] availableSizes = mStaticInfo.getAvailableSizesForFormatChecked(format,
-                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+                StaticMetadata.StreamDirection.Output);
 
         // for each resolution, test imageReader:
         for (Size sz : availableSizes) {
@@ -252,8 +278,6 @@
 
                 // Start capture.
                 CaptureRequest request = prepareCaptureRequest();
-                boolean repeating =
-                        (format != ImageFormat.JPEG && format != ImageFormat.RAW_SENSOR);
                 SimpleCaptureListener listener = new SimpleCaptureListener();
                 startCapture(request, repeating, listener, mHandler);
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index e6cb543..ab9cddc 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -17,7 +17,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.media.CamcorderProfile;
 import android.media.MediaCodecInfo;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
index 425f984..9f0af9b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -21,11 +21,9 @@
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraMetadata.Key;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureListener;
 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
 import android.hardware.camera2.cts.helpers.Camera2Focuser;
@@ -35,6 +33,7 @@
 import android.os.Build;
 import android.os.ConditionVariable;
 import android.util.Log;
+import android.util.Rational;
 
 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
 
@@ -97,6 +96,7 @@
     private static final int MAX_REGIONS_AF_INDEX = 2;
     private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 3000;
     private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2;
+    private static final int NUM_FRAMES_WAITED = 30;
 
     @Override
     protected void setUp() throws Exception {
@@ -129,7 +129,7 @@
      * Test normal still capture sequence.
      * <p>
      * Preview and and jpeg output streams are configured. Max still capture
-     * size is used for jpeg capture. The sequnce of still capture being test
+     * size is used for jpeg capture. The sequence of still capture being test
      * is: start preview, auto focus, precapture metering (if AE is not
      * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode
      * is CONTINUOUS_PICTURE.
@@ -316,6 +316,59 @@
     }
 
     /**
+     * Test preview is still running after a still request
+     */
+    public void testPreviewPersistence() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.i(TAG, "Testing preview persistence for Camera " + id);
+                openDevice(id);
+                previewPersistenceTestByCamera();
+            } finally {
+                closeDevice();
+                closeImageReader();
+            }
+        }
+    }
+
+    /**
+     * Start preview,take a picture and test preview is still running after snapshot
+     */
+    private void previewPersistenceTestByCamera() throws Exception {
+        Size maxStillSz = mOrderedStillSizes.get(0);
+        Size maxPreviewSz = mOrderedPreviewSizes.get(0);
+
+        SimpleCaptureListener resultListener = new SimpleCaptureListener();
+        SimpleCaptureListener stillResultListener = new SimpleCaptureListener();
+        SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
+        CaptureRequest.Builder previewRequest =
+                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+        CaptureRequest.Builder stillRequest =
+                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+        prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
+                maxStillSz, resultListener, imageListener);
+
+        // make sure preview is actually running
+        waitForNumResults(resultListener, NUM_FRAMES_WAITED);
+
+        // take a picture
+        CaptureRequest request = stillRequest.build();
+        mCamera.capture(request, stillResultListener, mHandler);
+        stillResultListener.getCaptureResultForRequest(request,
+                WAIT_FOR_RESULT_TIMEOUT_MS);
+
+        // validate image
+        Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+        validateJpegCapture(image, maxStillSz);
+
+        // make sure preview is still running after still capture
+        waitForNumResults(resultListener, NUM_FRAMES_WAITED);
+
+        stopPreview();
+        return;
+    }
+
+    /**
      * Take a picture for a given set of 3A regions for a particular camera.
      * <p>
      * Before take a still capture, it triggers an auto focus and lock it first,
@@ -406,7 +459,7 @@
                 previewRequest.get(CaptureRequest.CONTROL_AWB_MODE),
                 result.get(CaptureResult.CONTROL_AWB_MODE));
         if (canSetAwbRegion) {
-            int[] resultAwbRegions = getValueNotNull(result, CaptureRequest.CONTROL_AWB_REGIONS);
+            int[] resultAwbRegions = getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS);
             mCollector.expectEquals("AWB regions in result and request should be same",
                     toObject(awbRegions),
                     toObject(resultAwbRegions));
@@ -419,8 +472,8 @@
         boolean canSetAeRegion =
                 (aeRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX);
         if (canSetAeRegion) {
-            previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, awbRegions);
-            stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, awbRegions);
+            previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
+            stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
         }
         mCamera.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
@@ -433,7 +486,7 @@
                 previewRequest.get(CaptureRequest.CONTROL_AE_MODE),
                 result.get(CaptureResult.CONTROL_AE_MODE));
         if (canSetAeRegion) {
-            int[] resultAeRegions = getValueNotNull(result, CaptureRequest.CONTROL_AE_REGIONS);
+            int[] resultAeRegions = getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS);
             mCollector.expectEquals("AE regions in result and request should be same",
                     toObject(aeRegions),
                     toObject(resultAeRegions));
@@ -451,7 +504,7 @@
                 stillRequest.get(CaptureRequest.CONTROL_AF_MODE),
                 result.get(CaptureResult.CONTROL_AF_MODE));
         if (canSetAfRegion) {
-            int[] resultAfRegions = getValueNotNull(result, CaptureRequest.CONTROL_AF_REGIONS);
+            int[] resultAfRegions = getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS);
             mCollector.expectEquals("AF regions in result and request should be same",
                     toObject(afRegions),
                     toObject(resultAfRegions));
@@ -466,8 +519,6 @@
         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
         validateJpegCapture(image, maxStillSz);
 
-        // stopPreview must be called here to make sure next time a preview stream
-        // is created with new size.
         stopPreview();
     }
 
@@ -668,7 +719,7 @@
             mCollector.expectEquals("JPEG thumbnail size result and request should match",
                     testThumbnailSizes[i],
                     stillResult.get(CaptureResult.JPEG_THUMBNAIL_SIZE));
-            Key<double[]> gpsCoordsKey = CaptureResult.JPEG_GPS_COORDINATES;
+            CaptureResult.Key<double[]> gpsCoordsKey = CaptureResult.JPEG_GPS_COORDINATES;
             if (mCollector.expectKeyValueNotNull(stillResult, gpsCoordsKey) != null) {
                 mCollector.expectEquals("GPS coordinates result and request should match.",
                         toObject(EXIF_TEST_DATA[i].gpsCoordinates),
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
index 84ed37f..d569fab 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
@@ -23,7 +23,8 @@
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Size;
+import android.hardware.camera2.TotalCaptureResult;
+import android.util.Size;
 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureListener;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.util.Log;
@@ -122,6 +123,7 @@
         final int FPS_RANGE_SIZE = 2;
         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
         int[] fpsRanges = mStaticInfo.getAeAvailableTargetFpsRangesChecked();
+        boolean antiBandingOffIsSupported = mStaticInfo.isAntiBandingOffModeSupported();
         int[] fpsRange = new int[FPS_RANGE_SIZE];
         CaptureRequest.Builder requestBuilder =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
@@ -133,6 +135,19 @@
             fpsRange[1] = fpsRanges[i + 1];
 
             requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
+            // Turn off auto antibanding to avoid exposure time and frame duration interference
+            // from antibanding algorithm.
+            if (antiBandingOffIsSupported) {
+                requestBuilder.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
+                        CaptureRequest.CONTROL_AE_ANTIBANDING_MODE_OFF);
+            } else {
+                // The device doesn't implement the OFF mode, test continues. It need make sure
+                // that the antibanding algorithm doesn't interfere with the fps range control.
+                Log.i(TAG, "OFF antibanding mode is not supported, the camera device output must" +
+                        " satisfy the specified fps range regardless of its current antibanding" +
+                        " mode");
+            }
+
             resultListener = new SimpleCaptureListener();
             mCamera.setRepeatingRequest(requestBuilder.build(), resultListener, mHandler);
 
@@ -219,10 +234,10 @@
         stopPreview();
     }
 
-    private class IsCaptureResultValid extends ArgumentMatcher<CaptureResult> {
+    private class IsCaptureResultValid extends ArgumentMatcher<TotalCaptureResult> {
         @Override
         public boolean matches(Object obj) {
-            CaptureResult result = (CaptureResult)obj;
+            TotalCaptureResult result = (TotalCaptureResult)obj;
             Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
             if (timeStamp != null && timeStamp.longValue() > 0L) {
                 return true;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
index 0ed1eed..b1fd4a1 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
@@ -23,6 +23,7 @@
 import android.hardware.camera2.CameraDevice.CaptureListener;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
 import android.os.Handler;
 import android.util.Log;
 import android.view.Surface;
@@ -355,7 +356,7 @@
 
             @Override
             public void onCaptureCompleted(CameraDevice camera, CaptureRequest request,
-                    CaptureResult result) {
+                    TotalCaptureResult result) {
                     dispatchToFocuser(result);
             }
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java
index 86e264d..689bb0d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java
@@ -16,10 +16,10 @@
 
 package android.hardware.camera2.cts.helpers;
 
-import android.hardware.camera2.CameraMetadata.Key;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureRequest.Builder;
 import android.hardware.camera2.CaptureResult;
+import android.util.Log;
 
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matcher;
@@ -36,6 +36,10 @@
  * instead of failing the test immediately for each failure.
  */
 public class CameraErrorCollector extends ErrorCollector {
+
+    private static final String TAG = "CameraErrorCollector";
+    private static final boolean LOG_ERRORS = Log.isLoggable(TAG, Log.ERROR);
+
     private String mCameraMsg = "";
 
     @Override
@@ -50,7 +54,7 @@
      * @param message A string containing the failure reason.
      */
     public void addMessage(String message) {
-        super.addError(new Throwable(mCameraMsg + message));
+        addErrorSuper(new Throwable(mCameraMsg + message));
     }
 
     /**
@@ -58,7 +62,12 @@
      */
     @Override
     public void addError(Throwable error) {
-        super.addError(new Throwable(mCameraMsg + error.getMessage(), error));
+        addErrorSuper(new Throwable(mCameraMsg + error.getMessage(), error));
+    }
+
+    private void addErrorSuper(Throwable error) {
+        if (LOG_ERRORS) Log.e(TAG, error.getMessage());
+        super.addError(error);
     }
 
     /**
@@ -297,7 +306,7 @@
      * @param key The {@link CaptureRequest} key to be checked.
      * @return The value of the key.
      */
-    public <T> T expectKeyValueNotNull(Builder request, Key<T> key) {
+    public <T> T expectKeyValueNotNull(Builder request, CaptureRequest.Key<T> key) {
 
         T value = request.get(key);
         if (value == null) {
@@ -314,7 +323,7 @@
      * @param key The {@link CaptureResult} key to be checked.
      * @return The value of the key.
      */
-    public <T> T expectKeyValueNotNull(CaptureResult result, Key<T> key) {
+    public <T> T expectKeyValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
         return expectKeyValueNotNull("", result, key);
     }
 
@@ -326,7 +335,7 @@
      * @param key The {@link CaptureResult} key to be checked.
      * @return The value of the key.
      */
-    public <T> T expectKeyValueNotNull(String msg, CaptureResult result, Key<T> key) {
+    public <T> T expectKeyValueNotNull(String msg, CaptureResult result, CaptureResult.Key<T> key) {
 
         T value = result.get(key);
         if (value == null) {
@@ -343,7 +352,8 @@
      * @param key The {@link CaptureRequest} key to be checked.
      * @param expected The expected value of the CaptureRequest key.
      */
-    public <T> void expectKeyValueNotEquals(Builder request, Key<T> key, T expected) {
+    public <T> void expectKeyValueNotEquals(
+            Builder request, CaptureRequest.Key<T> key, T expected) {
         if (request == null || key == null || expected == null) {
             throw new IllegalArgumentException("request, key and target shouldn't be null");
         }
@@ -364,7 +374,8 @@
      * @param key The {@link CaptureResult} key to be checked.
      * @param expected The expected value of the CaptureResult key.
      */
-    public <T> void expectKeyValueNotEquals(CaptureResult result, Key<T> key, T expected) {
+    public <T> void expectKeyValueNotEquals(
+            CaptureResult result, CaptureResult.Key<T> key, T expected) {
         if (result == null || key == null || expected == null) {
             throw new IllegalArgumentException("result, key and target shouldn't be null");
         }
@@ -387,7 +398,7 @@
      * @param key The {@link CaptureRequest} key to be checked.
      * @param expected The expected value of the CaptureRequest key.
      */
-    public <T> void expectKeyValueEquals(Builder request, Key<T> key, T expected) {
+    public <T> void expectKeyValueEquals(Builder request, CaptureRequest.Key<T> key, T expected) {
         if (request == null || key == null || expected == null) {
             throw new IllegalArgumentException("request, key and target shouldn't be null");
         }
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index c539fe7..e99d64a 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -19,12 +19,13 @@
 import android.graphics.Rect;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraCharacteristics.Key;
 import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CameraMetadata.Key;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.CameraTestUtils;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.util.Log;
+import android.util.Rational;
 
 import junit.framework.Assert;
 
@@ -65,6 +66,7 @@
     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2;
     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2;
     private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2);
+    private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8;
 
     // TODO: Consider making this work across any metadata object, not just camera characteristics
     private final CameraCharacteristics mCharacteristics;
@@ -327,6 +329,18 @@
         return modes;
     }
 
+    /**
+     * Check if the antibanding OFF mode is supported.
+     *
+     * @return true if antibanding OFF mode is supported, false otherwise.
+     */
+    public boolean isAntiBandingOffModeSupported() {
+        List<Byte> antiBandingModes =
+                Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked()));
+
+        return antiBandingModes.contains((byte)CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF);
+    }
+
     public Boolean getFlashInfoChecked() {
         Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE;
         Boolean hasFlash = getValueFromKeyNonNull(key);
@@ -340,7 +354,7 @@
     }
 
     public int[] getAvailableTestPatternModesChecked() {
-        CameraMetadata.Key<int[]> key =
+        Key<int[]> key =
                 CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES;
         int[] modes = getValueFromKeyNonNull(key);
 
@@ -604,7 +618,7 @@
             return 0;
         }
 
-        CameraMetadata.Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY;
+        Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY;
         Integer maxAnalogsensitivity = getValueFromKeyNonNull(key);
         int minSensitivity = getSensitivityMinimumOrDefault();
         int maxSensitivity = getSensitivityMaximumOrDefault();
@@ -633,7 +647,7 @@
      * @return hyperfocalDistance of this device, -1 if this tag is not available.
      */
     public float getHyperfocalDistanceChecked() {
-        CameraMetadata.Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE;
+        Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE;
         Float hyperfocalDistance = getValueFromKeyNonNull(key);
         if (hyperfocalDistance == null) {
             return -1;
@@ -783,7 +797,7 @@
      * @return AE available modes
      */
     public byte[] getAeAvailableModesChecked() {
-        CameraMetadata.Key<byte[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES;
+        Key<byte[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES;
         byte[] modes = getValueFromKeyNonNull(modesKey);
         if (modes == null) {
             modes = new byte[0];
@@ -799,7 +813,7 @@
                 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON));
 
         // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH
-        CameraMetadata.Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
+        Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
         Boolean hasFlash = getValueFromKeyNonNull(flashKey);
         if (hasFlash == null) {
             hasFlash = false;
@@ -844,7 +858,7 @@
      * unavailable.
      */
     public byte[] getAwbAvailableModesChecked() {
-        CameraMetadata.Key<byte[]> key =
+        Key<byte[]> key =
                 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES;
         byte[] awbModes = getValueFromKeyNonNull(key);
 
@@ -870,7 +884,7 @@
      * unavailable.
      */
     public byte[] getAfAvailableModesChecked() {
-        CameraMetadata.Key<byte[]> key =
+        Key<byte[]> key =
                 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES;
         byte[] afModes = getValueFromKeyNonNull(key);
 
@@ -896,7 +910,7 @@
      */
     public Size[] getRawOutputSizesChecked() {
         return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
-                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+                StreamDirection.Output);
     }
 
     /**
@@ -906,41 +920,63 @@
      */
     public Size[] getJpegOutputSizeChecked() {
         return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
-                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+                StreamDirection.Output);
     }
 
     /**
-     * Get available sizes for given format
+     * Used to determine the stream direction for various helpers that look up
+     * format or size information.
+     */
+    public enum StreamDirection {
+        /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */
+        Output,
+        /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */
+        Input
+    }
+
+    /**
+     * Get available sizes for given user-defined format.
+     *
+     * <p><strong>Does not</strong> work with implementation-defined format.</p>
      *
      * @param format The format for the requested size array.
      * @param direction The stream direction, input or output.
      * @return The sizes of the given format, empty array if no available size is found.
      */
-    public Size[] getAvailableSizesForFormatChecked(int format, int direction) {
-        final int NUM_ELEMENTS_IN_STREAM_CONFIG = 4;
-        ArrayList<Size> sizeList = new ArrayList<Size>();
-        CameraMetadata.Key<int[]> key =
-                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
-        int[] config = getValueFromKeyNonNull(key);
+    public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
+        Key<StreamConfigurationMap> key =
+                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
+        StreamConfigurationMap config = getValueFromKeyNonNull(key);
 
         if (config == null) {
             return new Size[0];
         }
 
-        checkTrueForKey(key, "array length is invalid", config.length
-                % NUM_ELEMENTS_IN_STREAM_CONFIG == 0);
-        // Round down to 4 boundary if it is not integer times of 4, to avoid array out of bound
-        // in case the above check fails.
-        int configLength = (config.length / NUM_ELEMENTS_IN_STREAM_CONFIG)
-                * NUM_ELEMENTS_IN_STREAM_CONFIG;
-        for (int i = 0; i < configLength; i += NUM_ELEMENTS_IN_STREAM_CONFIG) {
-            if (config[i] == format && config[i+3] == direction) {
-                sizeList.add(new Size(config[i+1], config[i+2]));
-            }
+        android.util.Size[] utilSizes;
+
+        switch (direction) {
+            case Output:
+                utilSizes = config.getOutputSizes(format);
+                break;
+            case Input:
+                utilSizes = config.getInputSizes(format);
+                break;
+            default:
+                throw new IllegalArgumentException("direction must be output or input");
         }
 
-        Size[] sizes = new Size[sizeList.size()];
-        return sizeList.toArray(sizes);
+        // TODO: Get rid of android.util.Size
+        if (utilSizes == null) {
+            Log.i(TAG, "This camera doesn't support format " + format + " for " + direction);
+            return new Size[0];
+        }
+
+        Size[] sizes = new Size[utilSizes.length];
+        for (int i = 0; i < utilSizes.length; ++i) {
+            sizes[i] = new Size(utilSizes[i].getWidth(), utilSizes[i].getHeight());
+        }
+
+        return sizes;
     }
 
     /**
@@ -950,7 +986,7 @@
      */
     public int[] getAeAvailableTargetFpsRangesChecked() {
         final int NUM_ELEMENTS_IN_FPS_RANGE = 2;
-        CameraMetadata.Key<int[]> key =
+        Key<int[]> key =
                 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
         int[] fpsRanges = getValueFromKeyNonNull(key);
 
@@ -986,7 +1022,7 @@
      * @return 0 if maxFrameDuration is null
      */
     public long getMaxFrameDurationChecked() {
-        CameraMetadata.Key<Long> key =
+        Key<Long> key =
                 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION;
         Long maxDuration = getValueFromKeyNonNull(key);
 
@@ -998,42 +1034,37 @@
     }
 
     /**
-     * Get available minimal frame durations for a given format.
+     * Get available minimal frame durations for a given user-defined format.
+     *
+     * <p><strong>Does not</strong> work with implementation-defined format.</p>
      *
      * @param format One of the format from {@link ImageFormat}.
      * @return HashMap of minimal frame durations for different sizes, empty HashMap
      *         if availableMinFrameDurations is null.
      */
     public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) {
-        final int NUM_ELEMENTS_IN_DURATIONS = 4;
-        CameraMetadata.Key<long[]> key =
-                CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
-        long[] minDurations = getValueFromKeyNonNull(key);
+
         HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>();
 
-        if (minDurations == null) {
+        Key<StreamConfigurationMap> key =
+                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
+        StreamConfigurationMap config = getValueFromKeyNonNull(key);
+
+        if (config == null) {
             return minDurationMap;
         }
 
-        checkTrueForKey(key, "array length is invalid", minDurations.length
-                % NUM_ELEMENTS_IN_DURATIONS == 0);
-        // Round down to 4 boundary if it is not integer times of 4, to avoid array out of bound
-        // in case the above check fails.
-        int durationLength = (minDurations.length / NUM_ELEMENTS_IN_DURATIONS)
-                * NUM_ELEMENTS_IN_DURATIONS;
-        for (int i = 0; i < durationLength; i += NUM_ELEMENTS_IN_DURATIONS) {
-            if (minDurations[i] == format) {
-                Size size = new Size((int)minDurations[i+1], (int)minDurations[i+2]);
-                Long value = minDurations[i + 3];
-                minDurationMap.put(size, value);
-            }
+        for (android.util.Size size : config.getOutputSizes(format)) {
+            long minFrameDuration = config.getOutputMinFrameDuration(format, size);
+
+            minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration);
         }
 
         return minDurationMap;
     }
 
     public byte[] getAvailableEdgeModesChecked() {
-        CameraMetadata.Key<byte[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
+        Key<byte[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
         byte[] edgeModes = getValueFromKeyNonNull(key);
 
         if (edgeModes == null) {
@@ -1052,7 +1083,7 @@
     }
 
     public byte[] getAvailableNoiseReductionModesChecked() {
-        CameraMetadata.Key<byte[]> key =
+        Key<byte[]> key =
                 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
         byte[] noiseReductionModes = getValueFromKeyNonNull(key);
 
@@ -1077,7 +1108,7 @@
      * @return default value if the value is null.
      */
     public Rational getAeCompensationStepChecked() {
-        CameraMetadata.Key<Rational> key =
+        Key<Rational> key =
                 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP;
         Rational compensationStep = getValueFromKeyNonNull(key);
 
@@ -1096,7 +1127,7 @@
      * @return default value if the value is null or malformed.
      */
     public int[] getAeCompensationRangeChecked() {
-        CameraMetadata.Key<int[]> key =
+        Key<int[]> key =
                 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE;
         int[] compensationRange = getValueFromKeyNonNull(key);
         float compensationStep = getAeCompensationStepChecked().toFloat();
@@ -1125,7 +1156,7 @@
      * @return available video stabilization modes, empty array if it is unavailable.
      */
     public byte[] getAvailableVideoStabilizationModesChecked() {
-        CameraMetadata.Key<byte[]> key =
+        Key<byte[]> key =
                 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
         byte[] modes = getValueFromKeyNonNull(key);
 
@@ -1149,7 +1180,7 @@
      * @return available optical stabilization modes, empty array if it is unavailable.
      */
     public byte[] getAvailableOpticalStabilizationChecked() {
-        CameraMetadata.Key<byte[]> key =
+        Key<byte[]> key =
                 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
         byte[] modes = getValueFromKeyNonNull(key);
 
@@ -1170,7 +1201,7 @@
      * @return available max digitial zoom, default value (1.0) if it is not available.
      */
     public float getAvailableMaxDigitalZoomChecked() {
-        CameraMetadata.Key<Float> key =
+        Key<Float> key =
                 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
         Float maxZoom = getValueFromKeyNonNull(key);
         if (maxZoom == null) {
@@ -1184,7 +1215,7 @@
     }
 
     public byte[] getAvailableSceneModesChecked() {
-        CameraMetadata.Key<byte[]> key =
+        Key<byte[]> key =
                 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
         byte[] modes = getValueFromKeyNonNull(key);
 
@@ -1203,7 +1234,7 @@
     }
 
     public byte[] getAvailableEffectModesChecked() {
-        CameraMetadata.Key<byte[]> key =
+        Key<byte[]> key =
                 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS;
         byte[] modes = getValueFromKeyNonNull(key);
 
@@ -1220,6 +1251,26 @@
     }
 
     /**
+     * Get max pipeline depth and do the sanity check.
+     *
+     * @return max pipeline depth, default value if it is not available.
+     */
+    public byte getPipelineMaxDepthChecked() {
+        Key<Byte> key =
+                CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH;
+        Byte maxDepth = getValueFromKeyNonNull(key);
+
+        if (maxDepth == null) {
+            return REQUEST_PIPELINE_MAX_DEPTH_MAX;
+        }
+
+        checkTrueForKey(key, " max pipeline depth should be no larger than "
+                + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX);
+
+        return maxDepth;
+    }
+
+    /**
      * Get the value in index for a fixed-size array from a given key.
      *
      * <p>If the camera device is incorrectly reporting values, log a warning and return
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationInfo.java b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationInfo.java
index 15a5ea6..3324783 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationInfo.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationInfo.java
@@ -20,7 +20,7 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.renderscript.Allocation;
 import android.renderscript.Element;
 import android.renderscript.RenderScript;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptGraph.java b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptGraph.java
index 9129a6d..56d8703 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptGraph.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptGraph.java
@@ -21,7 +21,7 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.helpers.MaybeNull;
 import android.hardware.camera2.cts.helpers.UncheckedCloseable;
 import android.hardware.camera2.cts.rs.Script.ParameterMap;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java
index e1cdf03..ae55cc9 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java
@@ -20,7 +20,7 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.RectF;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.ScriptC_crop_yuvf_420_to_yuvx_444;
 import android.hardware.camera2.cts.rs.AllocationInfo.ElementInfo;
 import android.renderscript.Element;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java
index 60dca59..fb76196 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java
@@ -18,7 +18,7 @@
 
 import static android.hardware.camera2.cts.helpers.Preconditions.*;
 
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.ScriptC_means_yuvx_444_1d_to_single;
 import android.hardware.camera2.cts.rs.AllocationInfo.ElementInfo;
 import android.renderscript.Element;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java
index 335e631..2776f96 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java
@@ -20,7 +20,7 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.RectF;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.ScriptC_means_yuvx_444_2d_to_1d;
 import android.hardware.camera2.cts.rs.AllocationInfo.ElementInfo;
 import android.util.Log;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
index 1af724b..75d91bf 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
@@ -24,7 +24,7 @@
 import android.hardware.camera2.CameraDevice.CaptureListener;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.cts.CameraTestUtils;
 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index 2ff550b..7470f24 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -34,10 +34,9 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraMetadata.Key;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.CameraDevice.CaptureListener;
 import android.hardware.camera2.cts.Camera2SurfaceViewStubActivity;
 import android.hardware.camera2.cts.CameraTestUtils;
@@ -282,7 +281,8 @@
      * seen before the result matching myRequest arrives, or each individual wait
      * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms.
      */
-    protected static <T> void waitForResultValue(SimpleCaptureListener listener, Key<T> resultKey,
+    protected static <T> void waitForResultValue(SimpleCaptureListener listener,
+            CaptureResult.Key<T> resultKey,
             T expectedValue, int numResultsWait) {
         List<T> expectedValues = new ArrayList<T>();
         expectedValues.add(expectedValue);
@@ -305,7 +305,8 @@
      * seen before the result matching myRequest arrives, or each individual wait
      * for result times out after {@value #WAIT_FOR_RESULT_TIMEOUT_MS}ms.
      */
-    protected static <T> void waitForAnyResultValue(SimpleCaptureListener listener, Key<T> resultKey,
+    protected static <T> void waitForAnyResultValue(SimpleCaptureListener listener,
+            CaptureResult.Key<T> resultKey,
             List<T> expectedValues, int numResultsWait) {
         if (numResultsWait < 0 || listener == null || expectedValues == null) {
             throw new IllegalArgumentException(
@@ -335,6 +336,26 @@
     }
 
     /**
+     * Wait for numResultWait frames
+     *
+     * @param resultListener The capture listener to get capture result back.
+     * @param numResultsWait Number of frame to wait
+     */
+    protected static void waitForNumResults(SimpleCaptureListener resultListener,
+            int numResultsWait) {
+        if (numResultsWait <= 0 || resultListener == null) {
+            throw new IllegalArgumentException(
+                    "Input must be positive number and listener must be non-null");
+        }
+
+        CaptureResult result;
+        for (int i = 0; i < numResultsWait; i++) {
+            result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+        }
+        return;
+    }
+
+    /**
      * Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED.
      *
      * @param resultListener The capture listener to get capture result back.
diff --git a/tests/tests/hardware/src/android/hardware/consumerir/cts/ConsumerIrTest.java b/tests/tests/hardware/src/android/hardware/consumerir/cts/ConsumerIrTest.java
index 395a69b..e06adac 100644
--- a/tests/tests/hardware/src/android/hardware/consumerir/cts/ConsumerIrTest.java
+++ b/tests/tests/hardware/src/android/hardware/consumerir/cts/ConsumerIrTest.java
@@ -77,12 +77,12 @@
 
         ConsumerIrManager.CarrierFrequencyRange[] freqs = mCIR.getCarrierFrequencies();
         // Transmit two seconds for min and max for each frequency range
-        int[] pattern = {1111, 2222, 3333, 4444, 5555, 6666, 7777, 8888, 9999};
-        long totalXmitTime = 0; // get the length of the pattern
+        int[] pattern = {11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 99999};
+        long totalXmitTimeNanos = 0; // get the length of the pattern
         for (int slice : pattern) {
-            totalXmitTime += slice;
+            totalXmitTimeNanos += slice * 1000; // add the time in nanoseconds
         }
-        double margin = 0.1; // max fraction xmit is allowed to be off timing
+        double margin = 0.5; // max fraction xmit is allowed to be off timing
 
         for (ConsumerIrManager.CarrierFrequencyRange range : freqs) {
             // test min freq
@@ -90,18 +90,18 @@
             mCIR.transmit(range.getMinFrequency(), pattern);
             long newTime = SystemClock.elapsedRealtimeNanos();
             String msg = String.format("Pattern length pattern:%d, actual:%d",
-                    totalXmitTime, newTime - currentTime);
-            assertTrue(msg, newTime - currentTime >= totalXmitTime * (1.0 - margin));
-            assertTrue(msg, newTime - currentTime <= totalXmitTime * (1.0 + margin));
+                    totalXmitTimeNanos, newTime - currentTime);
+            assertTrue(msg, newTime - currentTime >= totalXmitTimeNanos * (1.0 - margin));
+            assertTrue(msg, newTime - currentTime <= totalXmitTimeNanos * (1.0 + margin));
 
             // test max freq
             currentTime = SystemClock.elapsedRealtimeNanos();
             mCIR.transmit(range.getMaxFrequency(), pattern);
             newTime = SystemClock.elapsedRealtimeNanos();
             msg = String.format("Pattern length pattern:%d, actual:%d",
-                    totalXmitTime, newTime - currentTime);
-            assertTrue(msg, newTime - currentTime >= totalXmitTime * (1.0 - margin));
-            assertTrue(msg, newTime - currentTime <= totalXmitTime * (1.0 + margin));
+                    totalXmitTimeNanos, newTime - currentTime);
+            assertTrue(msg, newTime - currentTime >= totalXmitTimeNanos * (1.0 - margin));
+            assertTrue(msg, newTime - currentTime <= totalXmitTimeNanos * (1.0 + margin));
         }
     }
 
diff --git a/tests/tests/location/src/android/location/cts/LocationManagerTest.java b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
index 34bc0e4..ab11b3c 100644
--- a/tests/tests/location/src/android/location/cts/LocationManagerTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
@@ -267,40 +267,66 @@
      */
     public void testModeAndProviderApisConsistent() {
         ContentResolver cr = mContext.getContentResolver();
+
+        // Find out what the settings say about which providers are enabled
         int mode = Settings.Secure.getInt(
                 cr, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
         boolean gps = Settings.Secure.isLocationProviderEnabled(cr, LocationManager.GPS_PROVIDER);
         boolean nlp = Settings.Secure.isLocationProviderEnabled(
                 cr, LocationManager.NETWORK_PROVIDER);
 
-        // Assert that if there are no test providers enabled, LocationManager just returns the
-        // values from Settings.Secure.
+        // Find out location manager's opinion on the matter, making sure we dont' get spurious
+        // results from test versions of the two providers.
         forceRemoveTestProvider(LocationManager.GPS_PROVIDER);
         forceRemoveTestProvider(LocationManager.NETWORK_PROVIDER);
         boolean lmGps = mManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
         boolean lmNlp = mManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
-        assertEquals("Inconsistent GPS values", gps, lmGps);
-        assertEquals("Inconsistent NLP values", nlp, lmNlp);
 
-        // Assert that isLocationProviderEnabled() values are consistent with the location mode
+        // Location Manager will report provider as off if it doesn't know about it
+        boolean expectedGps = gps && deviceHasProvider(LocationManager.GPS_PROVIDER);
+        boolean expectedNlp = nlp && deviceHasProvider(LocationManager.NETWORK_PROVIDER);
+
+        // Assert LocationManager returned the values from Settings.Secure (assuming the device has
+        // the appropriate hardware).
+        assertEquals("Inconsistent GPS values", expectedGps, lmGps);
+        assertEquals("Inconsistent NLP values", expectedNlp, lmNlp);
+
         switch (mode) {
             case Settings.Secure.LOCATION_MODE_OFF:
-                assertFalse("Bad GPS for mode " + mode, gps);
-                assertFalse("Bad NLP for mode " + mode, nlp);
+                expectedGps = false;
+                expectedNlp = false;
                 break;
             case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
-                assertEquals("Bad GPS for mode " + mode, hasGpsFeature(), gps);
-                assertFalse("Bad NLP for mode " + mode, nlp);
+                expectedGps = true;
+                expectedNlp = false;
                 break;
             case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
-                assertFalse("Bad GPS for mode " + mode, gps);
-                assertTrue("Bad NLP for mode " + mode, nlp);
+                expectedGps = false;
+                expectedNlp = true;
                 break;
             case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
-                assertEquals("Bad GPS for mode " + mode, hasGpsFeature(), gps);
-                assertTrue("Bad NLP for mode " + mode, nlp);
+                expectedGps = true;
+                expectedNlp = true;
                 break;
         }
+
+        // Assert that isLocationProviderEnabled() values are consistent with the location mode
+        assertEquals("Bad GPS for mode " + mode, expectedGps, gps);
+        assertEquals("Bad NLP for mode " + mode, expectedNlp, nlp);
+    }
+
+    /**
+     * Returns true if the {@link LocationManager} reports that the device includes this flavor
+     * of location provider.
+     */
+    private boolean deviceHasProvider(String provider) {
+        List<String> providers = mManager.getAllProviders();
+        for (String aProvider : providers) {
+            if (aProvider.equals(provider)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index 8e2d6df..9adc887 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <semaphore.h>
 
 #include <android/native_window_jni.h>
 
@@ -35,6 +36,7 @@
 
 #include "ndk/NdkMediaExtractor.h"
 #include "ndk/NdkMediaCodec.h"
+#include "ndk/NdkMediaCrypto.h"
 #include "ndk/NdkMediaFormat.h"
 #include "ndk/NdkMediaMuxer.h"
 
@@ -79,6 +81,7 @@
 
 
 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
+
     simplevector<int> sizes;
     int numtracks = AMediaExtractor_getTrackCount(ex);
     sizes.add(numtracks);
@@ -248,7 +251,7 @@
             return NULL;
         } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
             codec[i] = AMediaCodec_createDecoderByType(mime);
-            AMediaCodec_configure(codec[i], format, NULL, 0);
+            AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0);
             AMediaCodec_start(codec[i]);
             sawInputEOS[i] = false;
             sawOutputEOS[i] = false;
@@ -358,6 +361,7 @@
     delete[] sawInputEOS;
     for (int i = 0; i < numtracks; i++) {
         AMediaFormat_delete(format[i]);
+        AMediaCodec_stop(codec[i]);
         AMediaCodec_delete(codec[i]);
     }
     delete[] format;
@@ -397,7 +401,7 @@
             return false;
         } else if (!strncmp(mime, "video/", 6)) {
             codec = AMediaCodec_createDecoderByType(mime);
-            AMediaCodec_configure(codec, format, window, 0);
+            AMediaCodec_configure(codec, format, window, NULL, 0);
             AMediaCodec_start(codec);
             AMediaExtractor_selectTrack(ex, i);
         }
@@ -447,12 +451,13 @@
         }
     }
 
+    AMediaCodec_stop(codec);
     AMediaCodec_delete(codec);
     AMediaExtractor_delete(ex);
     return true;
 }
 
-extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv *env,
+extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv */*env*/,
         jclass /*clazz*/, int infd, jlong inoffset, jlong insize, int outfd, jboolean webm) {
 
 
@@ -503,7 +508,7 @@
         info.flags = AMediaExtractor_getSampleFlags(ex);
 
         size_t idx = (size_t) AMediaExtractor_getSampleTrackIndex(ex);
-        AMediaMuxer_writeSampleData(muxer, idx, buf, info);
+        AMediaMuxer_writeSampleData(muxer, idx, buf, &info);
 
         AMediaExtractor_advance(ex);
     }
@@ -515,7 +520,7 @@
 
 }
 
-extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv *env,
+extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
         jclass /*clazz*/) {
     AMediaFormat* format = AMediaFormat_new();
     if (!format) {
@@ -568,3 +573,90 @@
     return true;
 }
 
+
+extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/,
+        jclass /*clazz*/, int fd, jlong offset, jlong size) {
+
+    AMediaExtractor *ex = AMediaExtractor_new();
+    int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
+    if (err != 0) {
+        ALOGE("setDataSource error: %d", err);
+        return false;
+    }
+
+    PsshInfo* info = AMediaExtractor_getPsshInfo(ex);
+    if (info == NULL) {
+        ALOGI("null pssh");
+        return false;
+    }
+
+    ALOGI("pssh has %u entries", info->numentries);
+    if (info->numentries != 2) {
+        return false;
+    }
+
+    for (size_t i = 0; i < info->numentries; i++) {
+        PsshEntry *entry = &info->entries[i];
+        ALOGI("entry uuid %02x%02x..%02x%02x, data size %u",
+                entry->uuid[0],
+                entry->uuid[1],
+                entry->uuid[14],
+                entry->uuid[15],
+                entry->datalen);
+
+        AMediaCrypto *crypto = AMediaCrypto_new(entry->uuid, entry->data, entry->datalen);
+        if (crypto) {
+            ALOGI("got crypto");
+            AMediaCrypto_delete(crypto);
+        } else {
+            ALOGI("no crypto");
+        }
+    }
+    return true;
+}
+
+extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/,
+        jclass /*clazz*/) {
+
+    size_t numsubsamples = 4;
+    uint8_t key[16] = { 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 };
+    uint8_t iv[16] = { 4,3,2,1,4,3,2,1,4,3,2,1,4,3,2,1 };
+    size_t clearbytes[4] = { 5, 6, 7, 8 };
+    size_t encryptedbytes[4] = { 8, 7, 6, 5 };
+
+    AMediaCodecCryptoInfo *ci =
+            AMediaCodecCryptoInfo_new(numsubsamples, key, iv, AMEDIACODECRYPTOINFO_MODE_CLEAR, clearbytes, encryptedbytes);
+
+    if (AMediaCodecCryptoInfo_getNumSubSamples(ci) != 4) {
+        ALOGE("numsubsamples mismatch");
+        return false;
+    }
+    uint8_t bytes[16];
+    AMediaCodecCryptoInfo_getKey(ci, bytes);
+    if (memcmp(key, bytes, 16) != 0) {
+        ALOGE("key mismatch");
+        return false;
+    }
+    AMediaCodecCryptoInfo_getIV(ci, bytes);
+    if (memcmp(iv, bytes, 16) != 0) {
+        ALOGE("IV mismatch");
+        return false;
+    }
+    if (AMediaCodecCryptoInfo_getMode(ci) != AMEDIACODECRYPTOINFO_MODE_CLEAR) {
+        ALOGE("mode mismatch");
+        return false;
+    }
+    size_t sizes[numsubsamples];
+    AMediaCodecCryptoInfo_getClearBytes(ci, sizes);
+    if (memcmp(clearbytes, sizes, sizeof(size_t) * numsubsamples)) {
+        ALOGE("clear size mismatch");
+        return false;
+    }
+    AMediaCodecCryptoInfo_getEncryptedBytes(ci, sizes);
+    if (memcmp(encryptedbytes, sizes, sizeof(size_t) * numsubsamples)) {
+        ALOGE("encrypted size mismatch");
+        return false;
+    }
+    return true;
+}
+
diff --git a/tests/tests/media/res/raw/psshtest.mp4 b/tests/tests/media/res/raw/psshtest.mp4
new file mode 100644
index 0000000..98ffeb0
--- /dev/null
+++ b/tests/tests/media/res/raw/psshtest.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 0230edc..1747afa 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -44,6 +44,7 @@
 public class AdaptivePlaybackTest extends MediaPlayerTestBase {
     private static final String TAG = "AdaptivePlaybackTest";
     private boolean sanity = false;
+    private static final int MIN_FRAMES_BEFORE_DRC = 2;
 
     public Iterable<Codec> H264(CodecFactory factory) {
         return factory.createCodecList(
@@ -466,6 +467,10 @@
             tests.add(
                 new Step("testing DRC with no reconfigure - init", this, c) {
                     public void run() throws Throwable {
+                        // FIXME wait 2 seconds to allow system to free up previous codecs
+                        try {
+                            Thread.sleep(2000);
+                        } catch (InterruptedException e) {}
                         mDecoder = new Decoder(c.name);
                         mDecoder.configureAndStart(stepFormat(), stepSurface());
                         mAdjustTimeUs = 0;
@@ -473,7 +478,7 @@
                         mQueuedFrames = 0;
                     }});
 
-            for (int i = NUM_FRAMES, ix = 0; i > 1; i--, ix++) {
+            for (int i = NUM_FRAMES, ix = 0; i >= MIN_FRAMES_BEFORE_DRC; i--, ix++) {
                 final int mediaIx = ix % c.mediaList.length;
                 final int segmentSize = i;
                 tests.add(
@@ -481,9 +486,9 @@
                             this, c, mediaIx) {
                         public void run() throws Throwable {
                             mQueuedFrames += segmentSize;
-                            boolean lastSequence = segmentSize == 2;
+                            boolean lastSequence = segmentSize == MIN_FRAMES_BEFORE_DRC;
                             if (sanity) {
-                                lastSequence = (segmentSize >> 1) <= 2;
+                                lastSequence = (segmentSize >> 1) <= MIN_FRAMES_BEFORE_DRC;
                             }
                             int frames = mDecoder.queueInputBufferRange(
                                     stepMedia(),
@@ -589,7 +594,7 @@
             };
         }
         public void addTests(TestList tests, Codec c) {
-            for (int drcFrame = 6; drcFrame > 1; drcFrame--) {
+            for (int drcFrame = 6; drcFrame >= MIN_FRAMES_BEFORE_DRC; drcFrame--) {
                 for (int eosFrame = 6; eosFrame >= 1; eosFrame--) {
                     tests.add(testStep(c, drcFrame, eosFrame));
                 }
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
index 184e128..fc27dfa 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
@@ -45,6 +45,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
 
 public class NativeDecoderTest extends MediaPlayerTestBase {
     private static final String TAG = "DecoderTest";
@@ -68,7 +71,7 @@
         System.loadLibrary("ctsmediacodec_jni");
         Log.i("@@@", "after loadlibrary");
     }
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -77,7 +80,7 @@
     }
 
     // check that native extractor behavior matches java extractor
-    
+
     public void testExtractor() throws Exception {
         testExtractor(R.raw.sinesweepogg);
         testExtractor(R.raw.sinesweepmp3lame);
@@ -85,13 +88,13 @@
         testExtractor(R.raw.sinesweepm4a);
         testExtractor(R.raw.sinesweepflac);
         testExtractor(R.raw.sinesweepwav);
-        
+
         testExtractor(R.raw.video_1280x720_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz);
         testExtractor(R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz);
         testExtractor(R.raw.video_1280x720_webm_vp9_309kbps_25fps_vorbis_stereo_128kbps_44100hz);
         testExtractor(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz);
         testExtractor(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz);
-        
+
         CtsTestServer foo = new CtsTestServer(mContext);
         testExtractor(foo.getAssetUrl("noiseandchirps.ogg"));
         testExtractor(foo.getAssetUrl("ringer.mp3"));
@@ -101,19 +104,19 @@
     private void testExtractor(String path) throws Exception {
         int[] jsizes = getSampleSizes(path);
         int[] nsizes = getSampleSizesNativePath(path);
-        
+
         //Log.i("@@@", Arrays.toString(jsizes));
         assertTrue("different samplesizes", Arrays.equals(jsizes, nsizes));
     }
-    
+
     private void testExtractor(int res) throws Exception {
         AssetFileDescriptor fd = mResources.openRawResourceFd(res);
-        
+
         int[] jsizes = getSampleSizes(
                 fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
         int[] nsizes = getSampleSizesNative(
                 fd.getParcelFileDescriptor().getFd(), fd.getStartOffset(), fd.getLength());
-        
+
         fd.close();
         //Log.i("@@@", Arrays.toString(jsizes));
         assertTrue("different samplesizes", Arrays.equals(jsizes, nsizes));
@@ -140,7 +143,7 @@
         foo.add(numtracks);
         for (int i = 0; i < numtracks; i++) {
             MediaFormat format = ex.getTrackFormat(i);
-            String mime = format.getString(MediaFormat.KEY_MIME); 
+            String mime = format.getString(MediaFormat.KEY_MIME);
             if (mime.startsWith("audio/")) {
                 foo.add(0);
                 foo.add(format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
@@ -186,7 +189,7 @@
         testDecoder(R.raw.sinesweepm4a);
         testDecoder(R.raw.sinesweepflac);
         testDecoder(R.raw.sinesweepwav);
-        
+
         testDecoder(R.raw.video_1280x720_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz);
         testDecoder(R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz);
         testDecoder(R.raw.video_1280x720_webm_vp9_309kbps_25fps_vorbis_stereo_128kbps_44100hz);
@@ -197,12 +200,12 @@
 
     private void testDecoder(int res) throws Exception {
         AssetFileDescriptor fd = mResources.openRawResourceFd(res);
-        
+
         int[] jdata = getDecodedData(
                 fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
         int[] ndata = getDecodedDataNative(
                 fd.getParcelFileDescriptor().getFd(), fd.getStartOffset(), fd.getLength());
-        
+
         fd.close();
         Log.i("@@@", Arrays.toString(jdata));
         Log.i("@@@", Arrays.toString(ndata));
@@ -226,7 +229,7 @@
         ByteBuffer[][] outbuffers = new ByteBuffer[numtracks][];
         for (int i = 0; i < numtracks; i++) {
             format[i] = ex.getTrackFormat(i);
-            String mime = format[i].getString(MediaFormat.KEY_MIME); 
+            String mime = format[i].getString(MediaFormat.KEY_MIME);
             if (mime.startsWith("audio/") || mime.startsWith("video/")) {
                 codec[i] = MediaCodec.createDecoderByType(mime);
                 codec[i].configure(format[i], null, null, 0);
@@ -239,9 +242,7 @@
             }
             ex.selectTrack(i);
         }
-        
-        // TODO get input and output buffers from codecs
-        
+
         boolean[] sawInputEOS = new boolean[numtracks];
         boolean[] sawOutputEOS = new boolean[numtracks];
         int eosCount = 0;
@@ -329,13 +330,13 @@
                 trackbytes[idx++] = src.get(j);
             }
         }
-        
+
         return trackbytes;
     }
 
     static void addSampleData(ArrayList<Integer> dst,
             ByteBuffer buf, int size, MediaFormat format) throws IOException{
-        
+
         Log.i("@@@", "addsample " + dst.size() + "/" + size);
         int width = format.getInteger(MediaFormat.KEY_WIDTH, size);
         int stride = format.getInteger(MediaFormat.KEY_STRIDE, width);
@@ -451,5 +452,40 @@
     }
 
     private static native boolean testFormatNative();
+
+    public void testPssh() throws Exception {
+        testPssh(R.raw.psshtest);
+    }
+
+    private void testPssh(int res) throws Exception {
+        AssetFileDescriptor fd = mResources.openRawResourceFd(res);
+
+        MediaExtractor ex = new MediaExtractor();
+        ex.setDataSource(fd.getParcelFileDescriptor().getFileDescriptor(),
+                fd.getStartOffset(), fd.getLength());
+        testPssh(ex);
+        ex.release();
+
+        boolean ret = testPsshNative(
+                fd.getParcelFileDescriptor().getFd(), fd.getStartOffset(), fd.getLength());
+        assertTrue("native pssh error", ret);
+    }
+
+    private static void testPssh(MediaExtractor ex) {
+        Map<UUID, byte[]> map = ex.getPsshInfo();
+        Set<UUID> keys = map.keySet();
+        for (UUID uuid: keys) {
+            Log.i("@@@", "uuid: " + uuid + ", data size " +
+                    map.get(uuid).length);
+        }
+    }
+
+    private static native boolean testPsshNative(int fd, long offset, long size);
+
+    public void testCryptoInfo() throws Exception {
+        assertTrue("native cryptoinfo failed, see log for details", testCryptoInfoNative());
+    }
+
+    private static native boolean testCryptoInfoNative();
 }
 
diff --git a/tests/tests/security/src/android/security/cts/SeccompBpfTest.java b/tests/tests/security/src/android/security/cts/SeccompBpfTest.java
index 1f13b78..b7d8f2e 100644
--- a/tests/tests/security/src/android/security/cts/SeccompBpfTest.java
+++ b/tests/tests/security/src/android/security/cts/SeccompBpfTest.java
@@ -24,6 +24,7 @@
 import android.content.ServiceConnection;
 import android.os.ConditionVariable;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
@@ -47,21 +48,14 @@
      */
     static final int MSG_TEST_ENDED_CLEAN = 2;
 
-    final private Messenger mMessenger = new Messenger(new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_TEST_STARTED:
-                    onTestStarted();
-                    break;
-                case MSG_TEST_ENDED_CLEAN:
-                    onTestEnded(false);
-                    break;
-                default:
-                    super.handleMessage(msg);
-            }
-        }
-    });
+    /**
+     * Dedicated thread used to receive messages from the SeccompDeathTestService.
+     */
+    final private HandlerThread mHandlerThread = new HandlerThread("SeccompBpfTest handler");
+    /**
+     * Messenger that runs on mHandlerThread.
+     */
+    private Messenger mMessenger;
 
     /**
      * Condition that blocks the test/instrumentation thread that runs the
@@ -124,6 +118,36 @@
         assertTrue(mTestEnded);
     }
 
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mHandlerThread.start();
+        mMessenger = new Messenger(new Handler(mHandlerThread.getLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_TEST_STARTED:
+                        onTestStarted();
+                        break;
+                    case MSG_TEST_ENDED_CLEAN:
+                        onTestEnded(false);
+                        break;
+                    default:
+                        super.handleMessage(msg);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        try {
+            mHandlerThread.quitSafely();
+        } finally {
+            super.tearDown();
+        }
+    }
+
     private void launchDeathTestService() {
         Log.d(TAG, "launchDeathTestService");
         mCondition.close();
diff --git a/tests/tests/text/src/android/text/cts/EmojiTest.java b/tests/tests/text/src/android/text/cts/EmojiTest.java
index f5f191f..4bcc0e1 100644
--- a/tests/tests/text/src/android/text/cts/EmojiTest.java
+++ b/tests/tests/text/src/android/text/cts/EmojiTest.java
@@ -25,6 +25,7 @@
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.View;
+import android.webkit.cts.NullWebViewUtils;
 import android.webkit.cts.WebViewOnUiThread;
 import android.widget.TextView;
 import android.widget.EditText;
@@ -58,7 +59,6 @@
      */
     public void testEmojiGlyph() {
         CaptureCanvas ccanvas = new CaptureCanvas(getInstrumentation().getContext());
-        CaptureWebView cwebview = new CaptureWebView(getInstrumentation().getContext());
 
         Bitmap mBitmapA, mBitmapB;  // Emoji displayed Bitmaps to compare
 
@@ -92,11 +92,15 @@
 
             assertFalse(mBitmapA.sameAs(mBitmapB));
 
-            mBitmapA = cwebview.capture(Character.toChars(comparedCodePoints[i][0]));
-            mBitmapB = cwebview.capture(Character.toChars(comparedCodePoints[i][1]));
-
-            assertFalse(mBitmapA.sameAs(mBitmapB));
-
+            // Trigger activity bringup so we can determine if a WebView is available on this
+            // device.
+            EmojiStubActivity activity = getActivity();
+            if (NullWebViewUtils.isWebViewAvailable()) {
+                CaptureWebView cwebview = new CaptureWebView(getInstrumentation().getContext());
+                mBitmapA = cwebview.capture(Character.toChars(comparedCodePoints[i][0]));
+                mBitmapB = cwebview.capture(Character.toChars(comparedCodePoints[i][1]));
+                assertFalse(mBitmapA.sameAs(mBitmapB));
+            }
         }
     }
 
diff --git a/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java b/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java
index 086dce1..77de0b4 100644
--- a/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java
+++ b/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.test.ActivityInstrumentationTestCase2;
 
@@ -85,7 +86,7 @@
     }
 
     public void testGetActionBar_DeviceDefault_Light_DialogWhenLarge() {
-        assertActionBarWhenLarge(android.R.style.Theme_Holo_Light_DialogWhenLarge);
+        assertActionBarWhenLarge(android.R.style.Theme_DeviceDefault_Light_DialogWhenLarge);
     }
 
     public void testGetActionBar_DeviceDefault_Light_DialogWhenLarge_NoActionBar() {
@@ -122,6 +123,10 @@
 
     private void assertGetActionBar(int themeId, boolean actionBar) {
         Activity activity = startActivity(themeId);
+        if (activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            assertNull(activity.getActionBar());
+            return;
+        }
         if (actionBar) {
             assertNotNull(activity.getActionBar());
         } else {
diff --git a/tests/tests/tv/AndroidManifest.xml b/tests/tests/tv/AndroidManifest.xml
index f00361e..553f93b 100644
--- a/tests/tests/tv/AndroidManifest.xml
+++ b/tests/tests/tv/AndroidManifest.xml
@@ -22,12 +22,20 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
         <uses-library android:name="android.test.runner"/>
-        <service android:name="android.tv.cts.TvInputManagerTest$MockTvInputService"
+        <service android:name="android.tv.cts.TvInputManagerTest$MockTvInputInternalService"
                 android:permission="android.permission.BIND_TV_INPUT">
             <intent-filter>
                 <action android:name="android.tv.TvInputService" />
             </intent-filter>
         </service>
+        <service android:name="android.tv.cts.TvInputManagerTest$MockTvInputRemoteService"
+                android:permission="android.permission.BIND_TV_INPUT"
+                android:process=":remoteTvInputForTest"
+                android:isolatedProcess="true">
+            <intent-filter>
+                <action android:name="android.tv.TvInputService" />
+            </intent-filter>
+        </service>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/tv/src/android/tv/cts/TvInputManagerTest.java b/tests/tests/tv/src/android/tv/cts/TvInputManagerTest.java
index 931b38f..2b19963 100644
--- a/tests/tests/tv/src/android/tv/cts/TvInputManagerTest.java
+++ b/tests/tests/tv/src/android/tv/cts/TvInputManagerTest.java
@@ -17,16 +17,19 @@
 package android.tv.cts;
 
 import android.content.ComponentName;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.provider.TvContract;
 import android.test.AndroidTestCase;
+import android.text.TextUtils;
 import android.tv.TvInputInfo;
 import android.tv.TvInputManager;
 import android.tv.TvInputManager.Session;
-import android.tv.TvInputManager.SessionCreateCallback;
+import android.tv.TvInputManager.SessionCallback;
 import android.tv.TvInputManager.TvInputListener;
 import android.tv.TvInputService;
 import android.tv.TvInputService.TvInputSessionImpl;
@@ -41,28 +44,38 @@
  */
 public class TvInputManagerTest extends AndroidTestCase {
     private static final String TAG = "TvInputManagerTest";
-    private static final long OPERATION_TIMEOUT_MS = 500;
+    private static final long OPERATION_TIMEOUT_MS = 1500;
 
     private TvInputManager mManager;
     private Session mSession;
-    private SessionCreateCallback mSessionCallback;
+    private SessionCallback mSessionCallback;
     private boolean mAvailability;
     private TvInputListener mTvInputListener;
     private HandlerThread mCallbackThread;
     private Handler mCallbackHandler;
+
     private CountDownLatch mAvailabilityChangeLatch;
     private CountDownLatch mSessionCreationLatch;
+    private CountDownLatch mSessionReleaseLatch;
 
     public TvInputManagerTest() {
-        mSessionCallback = new MockSessionCreateCallback();
+        mSessionCallback = new MockSessionCallback();
     }
 
     @Override
     public void setContext(Context context) {
         super.setContext(context);
-        if (MockTvInputService.sComponentName == null) {
-            MockTvInputService.sComponentName = new ComponentName(
-                    context.getPackageName(), MockTvInputService.class.getName());
+        if (TextUtils.isEmpty(MockTvInputInternalService.sInputId)) {
+            ComponentName componentName = new ComponentName(
+                    context.getPackageName(), MockTvInputInternalService.class.getName());
+            // TODO: Do not directly generate an input id.
+            MockTvInputInternalService.sInputId = componentName.flattenToShortString();
+        }
+        if (TextUtils.isEmpty(MockTvInputRemoteService.sInputId)) {
+            ComponentName componentName = new ComponentName(
+                    context.getPackageName(), MockTvInputRemoteService.class.getName());
+            // TODO: Do not directly generate an input id.
+            MockTvInputRemoteService.sInputId = componentName.flattenToShortString();
         }
         mManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
     }
@@ -71,9 +84,9 @@
     protected void setUp() {
         mAvailability = false;
         mSession = null;
-        MockTvInputService.sInstance = null;
-        MockTvInputService.sSession = null;
-        MockTvInputService.sFailOnCreateSession = false;
+        MockTvInputInternalService.sInstance = null;
+        MockTvInputInternalService.sSession = null;
+        MockTvInputInternalService.sFailOnCreateSession = false;
         mCallbackThread = new HandlerThread("CallbackThread");
         mCallbackThread.start();
         mCallbackHandler = new Handler(mCallbackThread.getLooper());
@@ -82,7 +95,8 @@
     @Override
     protected void tearDown() throws InterruptedException {
         if (mTvInputListener != null) {
-            mManager.unregisterListener(MockTvInputService.sComponentName, mTvInputListener);
+            mManager.unregisterListener(MockTvInputInternalService.sInputId, mTvInputListener);
+            mManager.unregisterListener(MockTvInputRemoteService.sInputId, mTvInputListener);
             mTvInputListener = null;
         }
         mCallbackThread.quit();
@@ -90,35 +104,39 @@
     }
 
     public void testGetTvInputList() throws Exception {
-        // Check if the returned list includes the mock tv input service.
-        boolean mockServiceInstalled = false;
+        // Check if the returned list includes the mock tv input services.
+        int mockServiceInstalled = 0;
         for (TvInputInfo info : mManager.getTvInputList()) {
-            if (MockTvInputService.sComponentName.equals(info.getComponent())) {
-                mockServiceInstalled = true;
+            if (MockTvInputInternalService.sInputId.equals(info.getId())) {
+                ++mockServiceInstalled;
+            }
+            if (MockTvInputRemoteService.sInputId.equals(info.getId())) {
+                ++mockServiceInstalled;
             }
         }
 
         // Verify the result.
-        assertTrue("Mock service must be listed", mockServiceInstalled);
+        assertEquals("Mock services must be listed", 2, mockServiceInstalled);
     }
 
     public void testCreateSession() throws Exception {
         mSessionCreationLatch = new CountDownLatch(1);
         // Make the mock service return a session on request.
-        mManager.createSession(MockTvInputService.sComponentName, mSessionCallback,
+        mManager.createSession(MockTvInputInternalService.sInputId, mSessionCallback,
                 mCallbackHandler);
 
         // Verify the result.
         assertTrue(mSessionCreationLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertNotNull(mSession);
+
         mSession.release();
     }
 
     public void testCreateSessionFailure() throws Exception {
         mSessionCreationLatch = new CountDownLatch(1);
         // Make the mock service return {@code null} on request.
-        MockTvInputService.sFailOnCreateSession = true;
-        mManager.createSession(MockTvInputService.sComponentName, mSessionCallback,
+        MockTvInputInternalService.sFailOnCreateSession = true;
+        mManager.createSession(MockTvInputInternalService.sInputId, mSessionCallback,
                 mCallbackHandler);
 
         // Verify the result.
@@ -128,32 +146,78 @@
 
     public void testAvailabilityChanged() throws Exception {
         // Register a listener for availability change.
-        MockTvInputService.sInstanceLatch = new CountDownLatch(1);
+        MockTvInputInternalService.sInstanceLatch = new CountDownLatch(1);
         mTvInputListener = new MockTvInputListener();
-        mManager.registerListener(MockTvInputService.sComponentName, mTvInputListener,
+        mManager.registerListener(MockTvInputInternalService.sInputId, mTvInputListener,
                 mCallbackHandler);
 
         // Make sure that the mock service is created.
-        if (MockTvInputService.sInstance == null) {
-            assertTrue(MockTvInputService.sInstanceLatch.await(
+        if (MockTvInputInternalService.sInstance == null) {
+            assertTrue(MockTvInputInternalService.sInstanceLatch.await(
                     OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
 
         // Change the availability of the mock service.
-        mAvailability = mManager.getAvailability(MockTvInputService.sComponentName);
+        mAvailability = mManager.getAvailability(MockTvInputInternalService.sInputId);
         boolean newAvailiability = !mAvailability;
         mAvailabilityChangeLatch = new CountDownLatch(1);
-        MockTvInputService.sInstance.setAvailable(newAvailiability);
+        MockTvInputInternalService.sInstance.setAvailable(newAvailiability);
 
         // Verify the result.
         assertTrue(mAvailabilityChangeLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(newAvailiability, mAvailability);
     }
 
+    public void testCrashOnCreateSession() throws Exception {
+        mSessionCreationLatch = new CountDownLatch(
+                MockTvInputRemoteService.MAX_SESSION_CREATION_BEFORE_CRASH + 1);
+        mSessionReleaseLatch =  new CountDownLatch(
+                MockTvInputRemoteService.MAX_SESSION_CREATION_BEFORE_CRASH);
+        // availability should be changed three times:
+        // 1) false -> true, when connected, 2) true -> false after crash, and
+        // 3) false -> true, after reconnected.
+        mAvailabilityChangeLatch = new CountDownLatch(3);
+        mTvInputListener = new MockTvInputListener();
+        mManager.registerListener(MockTvInputRemoteService.sInputId, mTvInputListener,
+                mCallbackHandler);
+
+        for (int i = 0; i < MockTvInputRemoteService.MAX_SESSION_CREATION_BEFORE_CRASH + 1; ++i) {
+            mManager.createSession(MockTvInputRemoteService.sInputId, mSessionCallback,
+                    mCallbackHandler);
+        }
+
+        // Verify the result.
+        assertTrue(mSessionReleaseLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mSessionCreationLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(mAvailabilityChangeLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    public void testCrashOnTune() throws Exception {
+        mSessionCreationLatch = new CountDownLatch(1);
+        mSessionReleaseLatch =  new CountDownLatch(1);
+        // availability should be changed three times:
+        // 1) false -> true, when connected, 2) true -> false after crash, and
+        // 3) false -> true, after reconnected.
+        mAvailabilityChangeLatch = new CountDownLatch(3);
+
+        mTvInputListener = new MockTvInputListener();
+        mManager.registerListener(MockTvInputRemoteService.sInputId, mTvInputListener,
+                mCallbackHandler);
+        mManager.createSession(MockTvInputRemoteService.sInputId, mSessionCallback,
+                mCallbackHandler);
+
+        assertTrue(mSessionCreationLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        Uri channelUri = ContentUris.withAppendedId(TvContract.Channels.CONTENT_URI, 0);
+        mSession.tune(channelUri);
+        assertTrue(mSessionReleaseLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertNull(mSession);
+        assertTrue(mAvailabilityChangeLatch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
     private class MockTvInputListener extends TvInputListener {
         @Override
-        public void onAvailabilityChanged(ComponentName name, boolean isAvailable) {
-            assertEquals(MockTvInputService.sComponentName, name);
+        public void onAvailabilityChanged(String inputId, boolean isAvailable) {
             mAvailability = isAvailable;
             if (mAvailabilityChangeLatch != null) {
                 mAvailabilityChangeLatch.countDown();
@@ -161,7 +225,7 @@
         }
     }
 
-    private class MockSessionCreateCallback implements SessionCreateCallback {
+    private class MockSessionCallback extends SessionCallback {
         @Override
         public void onSessionCreated(Session session) {
             mSession = session;
@@ -169,12 +233,20 @@
                 mSessionCreationLatch.countDown();
             }
         }
+
+        @Override
+        public void onSessionReleased(Session session) {
+            mSession = null;
+            if (mSessionReleaseLatch != null) {
+                mSessionReleaseLatch.countDown();
+            }
+        }
     }
 
-    public static class MockTvInputService extends TvInputService {
-        static ComponentName sComponentName;
+    public static class MockTvInputInternalService extends TvInputService {
+        static String sInputId;
         static CountDownLatch sInstanceLatch;
-        static MockTvInputService sInstance;
+        static MockTvInputInternalService sInstance;
         static TvInputSessionImpl sSession;
 
         static boolean sFailOnCreateSession;
@@ -183,7 +255,7 @@
         public void onCreate() {
             super.onCreate();
             sInstance = this;
-            sSession = new MockTvInputSessionImpl();
+            sSession = new MockTvInputInternalSessionImpl();
             if (sInstanceLatch != null) {
                 sInstanceLatch.countDown();
             }
@@ -194,8 +266,8 @@
             return sFailOnCreateSession ? null : sSession;
         }
 
-        class MockTvInputSessionImpl extends TvInputSessionImpl {
-            public MockTvInputSessionImpl() { }
+        class MockTvInputInternalSessionImpl extends TvInputSessionImpl {
+            public MockTvInputInternalSessionImpl() { }
 
             @Override
             public void onRelease() { }
@@ -214,4 +286,49 @@
             }
         }
     }
+
+    public static class MockTvInputRemoteService extends TvInputService {
+        public static final int MAX_SESSION_CREATION_BEFORE_CRASH = 2;
+        static String sInputId;
+
+        private int mSessionCreationBeforeCrash;
+
+        @Override
+        public void onCreate() {
+            super.onCreate();
+            mSessionCreationBeforeCrash = MAX_SESSION_CREATION_BEFORE_CRASH;
+            setAvailable(true);
+        }
+
+        @Override
+        public TvInputSessionImpl onCreateSession() {
+            if (mSessionCreationBeforeCrash > 0) {
+                --mSessionCreationBeforeCrash;
+                return new MockTvInputRemoteSessionImpl();
+            }
+            android.os.Process.killProcess(android.os.Process.myPid());
+            return null;
+        }
+
+        class MockTvInputRemoteSessionImpl extends TvInputSessionImpl {
+            public MockTvInputRemoteSessionImpl() { }
+
+            @Override
+            public void onRelease() { }
+
+            @Override
+            public boolean onSetSurface(Surface surface) {
+                return false;
+            }
+
+            @Override
+            public void onSetVolume(float volume) { }
+
+            @Override
+            public boolean onTune(Uri channelUri) {
+                android.os.Process.killProcess(android.os.Process.myPid());
+                return false;
+            }
+        }
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/WindowTest.java b/tests/tests/view/src/android/view/cts/WindowTest.java
index afe5f0d..154c5cd 100644
--- a/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -997,6 +997,24 @@
         @Override
         public void takeInputQueue(InputQueue.Callback callback) {
         }
+
+        @Override
+        public void setStatusBarColor(int color) {
+        }
+
+        @Override
+        public int getStatusBarColor() {
+            return 0;
+        }
+
+        @Override
+        public void setNavigationBarColor(int color) {
+        }
+
+        @Override
+        public int getNavigationBarColor() {
+            return 0;
+        }
     }
 
     private class MockWindowCallback implements Window.Callback {
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
index a0b4fa6..ead235e 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
@@ -42,13 +42,19 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mOnUiThread = new WebViewOnUiThread(this, getActivity().getWebView());
+        WebView webview = getActivity().getWebView();
+        if (webview != null) {
+            mOnUiThread = new WebViewOnUiThread(this, webview);
 
-        mCookieManager = CookieManager.getInstance();
-        assertNotNull(mCookieManager);
+            mCookieManager = CookieManager.getInstance();
+            assertNotNull(mCookieManager);
+        }
     }
 
     public void testGetInstance() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mOnUiThread.cleanUp();
         CookieManager c1 = CookieManager.getInstance();
         CookieManager c2 = CookieManager.getInstance();
@@ -57,9 +63,15 @@
     }
 
     public void testClone() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
     }
 
     public void testAcceptCookie() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mCookieManager.removeAllCookie();
         mCookieManager.setAcceptCookie(false);
         assertFalse(mCookieManager.acceptCookie());
@@ -113,6 +125,9 @@
     }
 
     public void testCookieManager() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // enable cookie
         mCookieManager.setAcceptCookie(true);
         assertTrue(mCookieManager.acceptCookie());
@@ -146,6 +161,9 @@
 
     @SuppressWarnings("deprecation")
     public void testRemoveCookies() throws InterruptedException {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // enable cookie
         mCookieManager.setAcceptCookie(true);
         assertTrue(mCookieManager.acceptCookie());
@@ -212,6 +230,9 @@
     }
 
     public void testb3167208() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         String uri = "http://host.android.com/path/";
         // note the space after the domain=
         String problemCookie = "foo=bar; domain= .android.com; path=/";
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java
index 67a77e7..e2112b7 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java
@@ -33,6 +33,9 @@
     }
 
     public void testCookieSyncManager() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         CookieSyncManager csm1 = CookieSyncManager.createInstance(getActivity());
         assertNotNull(csm1);
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
index 0c0396a..704ae24 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
@@ -16,22 +16,30 @@
 
 package android.webkit.cts;
 
-import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
 
 /**
  * Original framework tests for CookieManager
  */
-public class CookieTest extends AndroidTestCase {
+public class CookieTest extends ActivityInstrumentationTestCase2<CookieSyncManagerStubActivity> {
 
     private CookieManager mCookieManager;
     private static final long WAIT_TIME = 50;
 
+    public CookieTest() {
+        super("com.android.cts.stub", CookieSyncManagerStubActivity.class);
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        CookieSyncManager.createInstance(getContext());
+
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         mCookieManager = CookieManager.getInstance();
         mCookieManager.removeAllCookie();
         // cookies are removed asynchronously, wait a bit for cookies to be removed
@@ -48,6 +56,9 @@
     }
 
     public void testDomain() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         String url = "http://www.foo.com";
 
         // basic
@@ -86,6 +97,9 @@
     }
 
     public void testSubDomain() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         String url_abcd = "http://a.b.c.d.com";
         String url_bcd = "http://b.c.d.com";
         String url_cd = "http://c.d.com";
@@ -127,6 +141,9 @@
     }
 
     public void testInvalidDomain() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         String url = "http://foo.bar.com";
 
         mCookieManager.setCookie(url, "a=1; domain=.yo.foo.bar.com");
@@ -163,6 +180,9 @@
     }
 
     public void testPath() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         String url = "http://www.foo.com";
 
         mCookieManager.setCookie(url, "a=b; path=/wee");
@@ -192,6 +212,9 @@
     }
 
     public void testEmptyValue() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         String url = "http://www.foobar.com";
 
         mCookieManager.setCookie(url, "bar=");
diff --git a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
index 016d7c2..8ab9eb6 100644
--- a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
@@ -135,49 +135,58 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        // Set up a WebView with JavaScript and Geolocation enabled
-        final String GEO_DIR = "geo_test";
-        mOnUiThread = new WebViewOnUiThread(this, getActivity().getWebView());
-        mOnUiThread.getSettings().setJavaScriptEnabled(true);
-        mOnUiThread.getSettings().setGeolocationEnabled(true);
-        mOnUiThread.getSettings().setGeolocationDatabasePath(
-                getActivity().getApplicationContext().getDir(GEO_DIR, 0).getPath());
+        WebView webview = getActivity().getWebView();
 
-        // Add a JsInterface to report back to the test when a location is received
-        mJavascriptStatusReceiver = new JavascriptStatusReceiver();
-        mOnUiThread.addJavascriptInterface(mJavascriptStatusReceiver, JS_INTERFACE_NAME);
+        if (webview != null) {
+            // Set up a WebView with JavaScript and Geolocation enabled
+            final String GEO_DIR = "geo_test";
+            mOnUiThread = new WebViewOnUiThread(this, webview);
+            mOnUiThread.getSettings().setJavaScriptEnabled(true);
+            mOnUiThread.getSettings().setGeolocationEnabled(true);
+            mOnUiThread.getSettings().setGeolocationDatabasePath(
+                    getActivity().getApplicationContext().getDir(GEO_DIR, 0).getPath());
 
-        // Always intercept all loads with the same geolocation test page
-        mOnUiThread.setWebViewClient(new InterceptClient(mOnUiThread));
-        // Clear all permissions before each test
-        GeolocationPermissions.getInstance().clearAll();
-        // Cache this mostly because the lookup is two lines of code
-        mLocationManager = (LocationManager)getActivity().getApplicationContext()
-                .getSystemService(Context.LOCATION_SERVICE);
-        // Add a test provider before each test to inject a location
-        mProviders = mLocationManager.getAllProviders();
-        for (String provider : mProviders) {
-            // Can't mock passive provider.
-            if (provider.equals(LocationManager.PASSIVE_PROVIDER)) {
-                mProviders.remove(provider);
-                break;
+            // Add a JsInterface to report back to the test when a location is received
+            mJavascriptStatusReceiver = new JavascriptStatusReceiver();
+            mOnUiThread.addJavascriptInterface(mJavascriptStatusReceiver, JS_INTERFACE_NAME);
+
+            // Always intercept all loads with the same geolocation test page
+            mOnUiThread.setWebViewClient(new InterceptClient(mOnUiThread));
+            // Clear all permissions before each test
+            GeolocationPermissions.getInstance().clearAll();
+            // Cache this mostly because the lookup is two lines of code
+            mLocationManager = (LocationManager)getActivity().getApplicationContext()
+                    .getSystemService(Context.LOCATION_SERVICE);
+            // Add a test provider before each test to inject a location
+            mProviders = mLocationManager.getAllProviders();
+            for (String provider : mProviders) {
+                // Can't mock passive provider.
+                if (provider.equals(LocationManager.PASSIVE_PROVIDER)) {
+                    mProviders.remove(provider);
+                    break;
+                }
             }
+            addTestProviders();
         }
-        addTestProviders();
     }
 
     @Override
     protected void tearDown() throws Exception {
         stopUpdateLocationThread();
-        // Remove the test provider after each test
-        for (String provider : mProviders) {
-            try {
-                // Work around b/11446702 by clearing the test provider before removing it
-                mLocationManager.clearTestProviderEnabled(provider);
-                mLocationManager.removeTestProvider(provider);
-            } catch (IllegalArgumentException e) {} // Not much to do about this
+        if (mProviders != null) {
+            // Remove the test provider after each test
+            for (String provider : mProviders) {
+                try {
+                    // Work around b/11446702 by clearing the test provider before removing it
+                    mLocationManager.clearTestProviderEnabled(provider);
+                    mLocationManager.removeTestProvider(provider);
+                } catch (IllegalArgumentException e) {} // Not much to do about this
+            }
         }
-        mOnUiThread.cleanUp();
+
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
         // This will null all member and static variables
         super.tearDown();
     }
@@ -278,6 +287,9 @@
 
     // Test loading a page and accepting the domain for one load
     public void testSimpleGeolocationRequestAcceptOnce() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final TestSimpleGeolocationRequestWebChromeClient chromeClientAcceptOnce =
                 new TestSimpleGeolocationRequestWebChromeClient(mOnUiThread, true, false);
         mOnUiThread.setWebChromeClient(chromeClientAcceptOnce);
@@ -368,6 +380,9 @@
 
     // Test loading a page and retaining the domain forever
     public void testSimpleGeolocationRequestAcceptAlways() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final TestSimpleGeolocationRequestWebChromeClient chromeClientAcceptAlways =
                 new TestSimpleGeolocationRequestWebChromeClient(mOnUiThread, true, true);
         mOnUiThread.setWebChromeClient(chromeClientAcceptAlways);
@@ -424,6 +439,9 @@
 
     // Test the GeolocationPermissions API
     public void testGeolocationPermissions() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         Set<String> acceptedOrigins = new TreeSet<String>();
         BooleanCheck falseCheck = new BooleanCheck(false);
         GeolocationPermissions.getInstance().getAllowed(URL_2, falseCheck);
@@ -483,6 +501,9 @@
 
     // Test loading pages and checks rejecting once and recjecting the domain forever
     public void testSimpleGeolocationRequestReject() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final TestSimpleGeolocationRequestWebChromeClient chromeClientRejectOnce =
                 new TestSimpleGeolocationRequestWebChromeClient(mOnUiThread, false, false);
         mOnUiThread.setWebChromeClient(chromeClientRejectOnce);
diff --git a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
index 52e9278..b078c7a 100644
--- a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
@@ -43,12 +43,18 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mOnUiThread = new WebViewOnUiThread(this, getActivity().getWebView());
+        WebView webview = getActivity().getWebView();
+        if (webview != null) {
+            mOnUiThread = new WebViewOnUiThread(this, webview);
+        }
     }
 
     @Override
     protected void tearDown() throws Exception {
-        mOnUiThread.cleanUp();
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
+
         if (mWebServer != null) {
             mWebServer.shutdown();
         }
@@ -138,6 +144,9 @@
     }
 
     public void testProceed() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mWebServer = new CtsTestServer(getActivity());
         String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
 
@@ -147,6 +156,9 @@
     }
 
     public void testCancel() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mWebServer = new CtsTestServer(getActivity());
         String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
 
@@ -159,6 +171,9 @@
     }
 
     public void testUseHttpAuthUsernamePassword() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mWebServer = new CtsTestServer(getActivity());
         String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
index 34dc697..71893f4 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
@@ -20,6 +20,7 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebHistoryItem;
+import android.webkit.WebView;
 
 
 public class WebBackForwardListTest extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
@@ -35,16 +36,24 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mOnUiThread = new WebViewOnUiThread(this, getActivity().getWebView());
+        WebView webview = getActivity().getWebView();
+        if (webview != null) {
+            mOnUiThread = new WebViewOnUiThread(this, webview);
+        }
     }
 
     @Override
     public void tearDown() throws Exception {
-        mOnUiThread.cleanUp();
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
         super.tearDown();
     }
 
     public void testGetCurrentItem() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         WebBackForwardList list = mOnUiThread.copyBackForwardList();
 
         assertNull(list.getCurrentItem());
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index 344b568..fca14e2 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -44,13 +44,18 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mOnUiThread = new WebViewOnUiThread(this, getActivity().getWebView());
+        WebView webview = getActivity().getWebView();
+        if (webview != null) {
+            mOnUiThread = new WebViewOnUiThread(this, webview);
+        }
         mWebServer = new CtsTestServer(getActivity());
     }
 
     @Override
     protected void tearDown() throws Exception {
-        mOnUiThread.cleanUp();
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
         if (mWebServer != null) {
             mWebServer.shutdown();
         }
@@ -62,6 +67,9 @@
     }
 
     public void testOnProgressChanged() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
@@ -78,6 +86,9 @@
     }
 
     public void testOnReceivedTitle() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
@@ -96,6 +107,9 @@
     }
 
     public void testOnReceivedIcon() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
@@ -161,20 +175,32 @@
         }
     }
     public void testWindows() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         runWindowTest(true);
     }
 
     public void testBlockWindowsSync() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mBlockWindowCreationSync = true;
         runWindowTest(false);
     }
 
     public void testBlockWindowsAsync() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mBlockWindowCreationAsync = true;
         runWindowTest(false);
     }
 
     public void testOnJsBeforeUnload() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
@@ -198,6 +224,9 @@
     }
 
     public void testOnJsAlert() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
@@ -220,6 +249,9 @@
     }
 
     public void testOnJsConfirm() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
@@ -242,6 +274,9 @@
     }
 
     public void testOnJsPrompt() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
index 468430f..7d276e9 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
@@ -54,12 +54,17 @@
     protected void setUp() throws Exception {
         super.setUp();
         mWebServer = new CtsTestServer(getActivity());
-        mOnUiThread = new WebViewOnUiThread(this, getActivity().getWebView());
+        WebView webview = getActivity().getWebView();
+        if (webview != null) {
+            mOnUiThread = new WebViewOnUiThread(this, webview);
+        }
     }
 
     @Override
     protected void tearDown() throws Exception {
-        mOnUiThread.cleanUp();
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
         mWebServer.shutdown();
         super.tearDown();
         if (mIconDb != null) {
@@ -69,6 +74,9 @@
     }
 
     public void testWebHistoryItem() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final WaitForIconClient waitForIconClient = new WaitForIconClient(mOnUiThread);
         mOnUiThread.setWebChromeClient(waitForIconClient);
         runTestOnUiThread(new Runnable() {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 291136f..c2104fe 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -65,8 +65,11 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mOnUiThread = new WebViewOnUiThread(this, getActivity().getWebView());
-        mSettings = mOnUiThread.getSettings();
+        WebView webview = getActivity().getWebView();
+        if (webview != null) {
+            mOnUiThread = new WebViewOnUiThread(this, webview);
+            mSettings = mOnUiThread.getSettings();
+        }
         mContext = getInstrumentation().getTargetContext();
     }
 
@@ -75,7 +78,9 @@
         if (mWebServer != null) {
             mWebServer.shutdown();
         }
-        mOnUiThread.cleanUp();
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
         super.tearDown();
     }
 
@@ -90,6 +95,9 @@
      * Safari/<major>.<minor>
      */
     public void testUserAgentString_default() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final String actualUserAgentString = mSettings.getUserAgentString();
         Log.i(LOG_TAG, String.format("Checking user agent string %s", actualUserAgentString));
         final String patternString =
@@ -131,6 +139,9 @@
     }
 
     public void testAccessUserAgentString() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         startWebServer();
         String url = mWebServer.getUserAgentUrl();
 
@@ -159,6 +170,9 @@
     }
 
     public void testAccessAllowFileAccess() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // This test is not compatible with 4.0.3
         if ("4.0.3".equals(Build.VERSION.RELEASE)) {
             return;
@@ -184,6 +198,9 @@
     }
 
     public void testAccessCacheMode() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -256,6 +273,9 @@
     }
 
     public void testAccessCursiveFontFamily() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getCursiveFontFamily());
 
         String newCusiveFamily = "Apple Chancery";
@@ -264,6 +284,9 @@
     }
 
     public void testAccessFantasyFontFamily() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getFantasyFontFamily());
 
         String newFantasyFamily = "Papyrus";
@@ -272,6 +295,9 @@
     }
 
     public void testAccessFixedFontFamily() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getFixedFontFamily());
 
         String newFixedFamily = "Courier";
@@ -280,6 +306,9 @@
     }
 
     public void testAccessSansSerifFontFamily() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getSansSerifFontFamily());
 
         String newFixedFamily = "Verdana";
@@ -288,6 +317,9 @@
     }
 
     public void testAccessSerifFontFamily() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getSerifFontFamily());
 
         String newSerifFamily = "Times";
@@ -296,6 +328,9 @@
     }
 
     public void testAccessStandardFontFamily() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getStandardFontFamily());
 
         String newStandardFamily = "Times";
@@ -304,6 +339,9 @@
     }
 
     public void testAccessDefaultFontSize() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         int defaultSize = mSettings.getDefaultFontSize();
         assertTrue(defaultSize > 0);
 
@@ -322,6 +360,9 @@
     }
 
     public void testAccessDefaultFixedFontSize() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         int defaultSize = mSettings.getDefaultFixedFontSize();
         assertTrue(defaultSize > 0);
 
@@ -340,6 +381,9 @@
     }
 
     public void testAccessDefaultTextEncodingName() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getDefaultTextEncodingName());
 
         String newEncodingName = "iso-8859-1";
@@ -348,6 +392,9 @@
     }
 
     public void testAccessJavaScriptCanOpenWindowsAutomatically() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mSettings.setJavaScriptEnabled(true);
 
         mSettings.setJavaScriptCanOpenWindowsAutomatically(false);
@@ -372,6 +419,9 @@
     }
 
     public void testAccessJavaScriptEnabled() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mSettings.setJavaScriptEnabled(true);
         assertTrue(mSettings.getJavaScriptEnabled());
         loadAssetUrl(TestHtmlConstants.JAVASCRIPT_URL);
@@ -395,6 +445,9 @@
     }
 
     public void testAccessLayoutAlgorithm() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertEquals(WebSettings.LayoutAlgorithm.NARROW_COLUMNS, mSettings.getLayoutAlgorithm());
 
         mSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
@@ -405,6 +458,9 @@
     }
 
     public void testAccessMinimumFontSize() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertEquals(8, mSettings.getMinimumFontSize());
 
         mSettings.setMinimumFontSize(100);
@@ -418,6 +474,9 @@
     }
 
     public void testAccessMinimumLogicalFontSize() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertEquals(8, mSettings.getMinimumLogicalFontSize());
 
         mSettings.setMinimumLogicalFontSize(100);
@@ -431,6 +490,9 @@
     }
 
     public void testAccessPluginsEnabled() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertFalse(mSettings.getPluginsEnabled());
 
         mSettings.setPluginsEnabled(true);
@@ -438,6 +500,9 @@
     }
 
     public void testAccessPluginsPath() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(mSettings.getPluginsPath());
 
         String pluginPath = "pluginPath";
@@ -447,6 +512,9 @@
     }
 
     public void testAccessSaveFormData() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertTrue(mSettings.getSaveFormData());
 
         mSettings.setSaveFormData(false);
@@ -454,6 +522,9 @@
     }
 
     public void testAccessTextSize() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertEquals(TextSize.NORMAL, mSettings.getTextSize());
 
         mSettings.setTextSize(TextSize.LARGER);
@@ -470,6 +541,9 @@
     }
 
     public void testAccessUseDoubleTree() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertFalse(mSettings.getUseDoubleTree());
 
         mSettings.setUseDoubleTree(true);
@@ -478,6 +552,9 @@
     }
 
     public void testAccessUseWideViewPort() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertFalse(mSettings.getUseWideViewPort());
 
         mSettings.setUseWideViewPort(true);
@@ -485,12 +562,18 @@
     }
 
     public void testSetNeedInitialFocus() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mSettings.setNeedInitialFocus(false);
 
         mSettings.setNeedInitialFocus(true);
     }
 
     public void testSetRenderPriority() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);
 
         mSettings.setRenderPriority(WebSettings.RenderPriority.LOW);
@@ -499,6 +582,9 @@
     }
 
     public void testAccessSupportMultipleWindows() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertFalse(mSettings.supportMultipleWindows());
 
         mSettings.setSupportMultipleWindows(true);
@@ -506,6 +592,9 @@
     }
 
     public void testAccessSupportZoom() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertTrue(mSettings.supportZoom());
 
         runTestOnUiThread(new Runnable() {
@@ -518,6 +607,9 @@
     }
 
     public void testAccessBuiltInZoomControls() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertFalse(mSettings.getBuiltInZoomControls());
 
         runTestOnUiThread(new Runnable() {
@@ -530,6 +622,9 @@
     }
 
     public void testAppCacheDisabled() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Test that when AppCache is disabled, we don't get any AppCache
         // callbacks.
         startWebServer();
@@ -549,6 +644,9 @@
     }
 
     public void testAppCacheEnabled() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Note that the AppCache path can only be set once. This limits the
         // amount of testing we can do, and means that we must test all aspects
         // of setting the AppCache path in a single test to guarantee ordering.
@@ -594,6 +692,9 @@
     // using a URL. Finally, it looks like enabling database requires creating a
     // webChromeClient and listening to Quota callbacks, which is not documented.
     public void testDatabaseDisabled() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Verify that websql database does not work when disabled.
         startWebServer();
 
@@ -612,6 +713,9 @@
     }
 
     public void testLoadsImagesAutomatically() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertTrue(mSettings.getLoadsImagesAutomatically());
 
         startWebServer();
@@ -644,6 +748,9 @@
     }
 
     public void testBlockNetworkImage() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertFalse(mSettings.getBlockNetworkImage());
 
         startWebServer();
@@ -673,6 +780,9 @@
     }
 
     public void testBlockNetworkLoads() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertFalse(mSettings.getBlockNetworkLoads());
 
         startWebServer();
@@ -709,6 +819,9 @@
 
     // Verify that an image in local file system can be loaded by an asset
     public void testLocalImageLoads() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
 
         mSettings.setJavaScriptEnabled(true);
         // Check that local images are loaded without issues regardless of domain checkings
@@ -723,6 +836,9 @@
     // Verify that javascript cross-domain request permissions matches file domain settings
     // for iframes
     public void testIframesWhenAccessFromFileURLsEnabled() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
 
         mSettings.setJavaScriptEnabled(true);
         // disable universal access from files
@@ -739,6 +855,9 @@
     // Verify that javascript cross-domain request permissions matches file domain settings
     // for iframes
     public void testIframesWhenAccessFromFileURLsDisabled() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
 
         mSettings.setJavaScriptEnabled(true);
         // disable universal access from files
@@ -757,11 +876,17 @@
 
     // Verify that enabling file access from file URLs enable XmlHttpRequest (XHR) across files
     public void testXHRWhenAccessFromFileURLsEnabled() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         verifyFileXHR(true);
     }
 
     // Verify that disabling file access from file URLs disable XmlHttpRequest (XHR) accross files
     public void testXHRWhenAccessFromFileURLsDisabled() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
 
         final ChromeClient webChromeClient = new ChromeClient(mOnUiThread);
         mOnUiThread.setWebChromeClient(webChromeClient);
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 9aca8c7..5907d2f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -47,18 +47,24 @@
     protected void setUp() throws Exception {
         super.setUp();
         final WebViewStubActivity activity = getActivity();
-        new PollingCheck(TEST_TIMEOUT) {
-            @Override
-                protected boolean check() {
-                return activity.hasWindowFocus();
-            }
-        }.run();
-        mOnUiThread = new WebViewOnUiThread(this, activity.getWebView());
+        WebView webview = activity.getWebView();
+        if (webview != null) {
+            new PollingCheck(TEST_TIMEOUT) {
+                @Override
+                    protected boolean check() {
+                    return activity.hasWindowFocus();
+                }
+            }.run();
+
+            mOnUiThread = new WebViewOnUiThread(this, webview);
+        }
     }
 
     @Override
     protected void tearDown() throws Exception {
-        mOnUiThread.cleanUp();
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
         if (mWebServer != null) {
             mWebServer.shutdown();
         }
@@ -67,12 +73,18 @@
 
     // Verify that the shouldoverrideurlloading is false by default
     public void testShouldOverrideUrlLoadingDefault() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final WebViewClient webViewClient = new WebViewClient();
         assertFalse(webViewClient.shouldOverrideUrlLoading(mOnUiThread.getWebView(), null));
     }
 
     // Verify shouldoverrideurlloading called on top level navigation
     public void testShouldOverrideUrlLoading() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         mOnUiThread.getSettings().setJavaScriptEnabled(true);
@@ -87,6 +99,9 @@
     // Verify shouldoverrideurlloading called on webview called via onCreateWindow
     // TODO(sgurun) upstream this test to Aw.
     public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mWebServer = new CtsTestServer(getActivity());
         // WebViewClient for main window
         final MockWebViewClient mainWebViewClient = new MockWebViewClient();
@@ -152,6 +167,9 @@
     }
 
     public void testLoadPage() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         mWebServer = new CtsTestServer(getActivity());
@@ -185,6 +203,9 @@
     }
 
     public void testOnReceivedError() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
 
@@ -196,6 +217,9 @@
     }
 
     public void testOnFormResubmission() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         final WebSettings settings = mOnUiThread.getSettings();
@@ -221,6 +245,9 @@
     }
 
     public void testDoUpdateVisitedHistory() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         mWebServer = new CtsTestServer(getActivity());
@@ -239,6 +266,9 @@
     }
 
     public void testOnReceivedHttpAuthRequest() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         mWebServer = new CtsTestServer(getActivity());
@@ -250,6 +280,9 @@
     }
 
     public void testShouldOverrideKeyEvent() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
 
@@ -257,6 +290,9 @@
     }
 
     public void testOnUnhandledKeyEvent() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         requireLoadedPage();
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
@@ -276,6 +312,9 @@
     }
 
     public void testOnScaleChanged() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         mWebServer = new CtsTestServer(getActivity());
@@ -301,6 +340,9 @@
     }
 
     private void requireLoadedPage() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
     }
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
index a7ee974..56f8f61 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
@@ -63,9 +63,17 @@
                 Log.i(TAG, "done setting cookie before creating webview");
             }
         });
+        NullWebViewUtils.NullWebViewFromThreadExceptionHandler h =
+                new NullWebViewUtils.NullWebViewFromThreadExceptionHandler();
+
+        background.setUncaughtExceptionHandler(h);
         background.start();
         background.join();
 
+        if (!h.isWebViewAvailable(mActivity)) {
+            return;
+        }
+
         // Now create WebView and test that setting the cookie beforehand really worked.
         mActivity.createAndAttachWebView();
         WebViewOnUiThread onUiThread = new WebViewOnUiThread(this, mActivity.getWebView());
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index d8d9f12..982acfc 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -131,23 +131,28 @@
     protected void setUp() throws Exception {
         super.setUp();
         final WebViewStubActivity activity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return activity.hasWindowFocus();
-            }
-        }.run();
         mWebView = activity.getWebView();
-        File f = activity.getFileStreamPath("snapshot");
-        if (f.exists()) {
-            f.delete();
+        if (mWebView != null) {
+            new PollingCheck() {
+                @Override
+                    protected boolean check() {
+                        return activity.hasWindowFocus();
+                }
+            }.run();
+            File f = activity.getFileStreamPath("snapshot");
+            if (f.exists()) {
+                f.delete();
+            }
+
+            mOnUiThread = new WebViewOnUiThread(this, mWebView);
         }
-        mOnUiThread = new WebViewOnUiThread(this, mWebView);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        mOnUiThread.cleanUp();
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
         if (mWebServer != null) {
             stopWebServer();
         }
@@ -178,6 +183,10 @@
 
     @UiThreadTest
     public void testConstructor() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         new WebView(getActivity());
         new WebView(getActivity(), null);
         new WebView(getActivity(), null, 0);
@@ -185,12 +194,19 @@
 
     @UiThreadTest
     public void testCreatingWebViewCreatesCookieSyncManager() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         new WebView(getActivity());
         assertNotNull(CookieSyncManager.getInstance());
     }
 
     @UiThreadTest
     public void testFindAddress() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         /*
          * Info about USPS
          * http://en.wikipedia.org/wiki/Postal_address#United_States
@@ -206,19 +222,25 @@
     @SuppressWarnings("deprecation")
     @UiThreadTest
     public void testGetZoomControls() {
-         WebSettings settings = mWebView.getSettings();
-         assertTrue(settings.supportZoom());
-         View zoomControls = mWebView.getZoomControls();
-         assertNotNull(zoomControls);
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        WebSettings settings = mWebView.getSettings();
+        assertTrue(settings.supportZoom());
+        View zoomControls = mWebView.getZoomControls();
+        assertNotNull(zoomControls);
 
-         // disable zoom support
-         settings.setSupportZoom(false);
-         assertFalse(settings.supportZoom());
-         assertNull(mWebView.getZoomControls());
+        // disable zoom support
+        settings.setSupportZoom(false);
+        assertFalse(settings.supportZoom());
+        assertNull(mWebView.getZoomControls());
     }
 
     @UiThreadTest
     public void testInvokeZoomPicker() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         WebSettings settings = mWebView.getSettings();
         assertTrue(settings.supportZoom());
         startWebServer(false);
@@ -228,6 +250,10 @@
     }
 
     public void testZoom() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         // Pinch zoom is not supported in wrap_content layouts.
         mOnUiThread.setLayoutHeightToMatchParent();
 
@@ -314,6 +340,10 @@
 
     @UiThreadTest
     public void testSetScrollBarStyle() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
         assertFalse(mWebView.overlayHorizontalScrollbar());
         assertFalse(mWebView.overlayVerticalScrollbar());
@@ -333,6 +363,10 @@
 
     @UiThreadTest
     public void testScrollBarOverlay() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         mWebView.setHorizontalScrollbarOverlay(true);
         mWebView.setVerticalScrollbarOverlay(false);
         assertTrue(mWebView.overlayHorizontalScrollbar());
@@ -346,6 +380,10 @@
 
     @UiThreadTest
     public void testLoadUrl() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         assertNull(mWebView.getUrl());
         assertNull(mWebView.getOriginalUrl());
         assertEquals(INITIAL_PROGRESS, mWebView.getProgress());
@@ -399,6 +437,10 @@
 
     @UiThreadTest
     public void testLoadUrlDoesNotStripParamsWhenLoadingContentUrls() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         Uri.Builder uriBuilder = new Uri.Builder().scheme(
                 ContentResolver.SCHEME_CONTENT).authority(MockContentProvider.AUTHORITY);
         uriBuilder.appendPath("foo.html").appendQueryParameter("param","bar");
@@ -411,6 +453,10 @@
 
     @UiThreadTest
     public void testAppInjectedXRequestedWithHeaderIsNotOverwritten() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         HashMap<String, String> map = new HashMap<String, String>();
@@ -430,6 +476,10 @@
 
     @UiThreadTest
     public void testAppCanInjectHeadersViaImmutableMap() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         HashMap<String, String> map = new HashMap<String, String>();
@@ -472,6 +522,10 @@
     @SuppressWarnings("deprecation")
     @UiThreadTest
     public void testGetVisibleTitleHeight() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         mOnUiThread.loadUrlAndWaitForCompletion(url);
@@ -480,6 +534,10 @@
 
     @UiThreadTest
     public void testGetOriginalUrl() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         startWebServer(false);
         final String finalUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         final String redirectUrl =
@@ -500,6 +558,10 @@
     }
 
     public void testStopLoading() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         assertEquals(INITIAL_PROGRESS, mOnUiThread.getProgress());
 
         startWebServer(false);
@@ -535,6 +597,10 @@
 
     @UiThreadTest
     public void testGoBackAndForward() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         assertGoBackOrForwardBySteps(false, -1);
         assertGoBackOrForwardBySteps(false, 1);
 
@@ -581,6 +647,10 @@
 
     @UiThreadTest
     public void testAddJavascriptInterface() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         WebSettings settings = mWebView.getSettings();
         settings.setJavaScriptEnabled(true);
         settings.setJavaScriptCanOpenWindowsAutomatically(true);
@@ -651,6 +721,10 @@
 
     @UiThreadTest
     public void testAddJavascriptInterfaceNullObject() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         WebSettings settings = mWebView.getSettings();
         settings.setJavaScriptEnabled(true);
         String setTitleToPropertyTypeHtml = "<html><head></head>" +
@@ -683,6 +757,10 @@
 
     @UiThreadTest
     public void testRemoveJavascriptInterface() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         WebSettings settings = mWebView.getSettings();
         settings.setJavaScriptEnabled(true);
         String setTitleToPropertyTypeHtml = "<html><head></head>" +
@@ -702,6 +780,10 @@
     }
 
     public void testUseRemovedJavascriptInterface() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         class RemovedObject {
             @Override
             @JavascriptInterface
@@ -785,6 +867,34 @@
         assertTrue(mJsInterfaceWasCalled.get());
     }
 
+    public void testJavascriptInterfaceCustomPropertiesClearedOnReload() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
+        mOnUiThread.getSettings().setJavaScriptEnabled(true);
+
+        class DummyJavaScriptInterface {
+        }
+        final DummyJavaScriptInterface obj = new DummyJavaScriptInterface();
+        mOnUiThread.addJavascriptInterface(obj, "dummy");
+        mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
+
+        EvaluateJsResultPollingCheck jsResult;
+        jsResult = new EvaluateJsResultPollingCheck("42");
+        mOnUiThread.evaluateJavascript("dummy.custom_property = 42", jsResult);
+        jsResult.run();
+        jsResult = new EvaluateJsResultPollingCheck("true");
+        mOnUiThread.evaluateJavascript("'custom_property' in dummy", jsResult);
+        jsResult.run();
+
+        mOnUiThread.reload();
+
+        jsResult = new EvaluateJsResultPollingCheck("false");
+        mOnUiThread.evaluateJavascript("'custom_property' in dummy", jsResult);
+        jsResult.run();
+    }
+
     private final class TestPictureListener implements PictureListener {
         public int callCount;
 
@@ -822,6 +932,9 @@
     }
 
     public void testCapturePicture() throws Exception, Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final TestPictureListener listener = new TestPictureListener();
 
         startWebServer(false);
@@ -846,6 +959,9 @@
     }
 
     public void testSetPictureListener() throws Exception, Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class MyPictureListener implements PictureListener {
             public int callCount;
             public WebView webView;
@@ -889,6 +1005,9 @@
 
     @UiThreadTest
     public void testAccessHttpAuthUsernamePassword() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         try {
             WebViewDatabase.getInstance(getActivity()).clearHttpAuthUsernamePassword();
 
@@ -950,6 +1069,9 @@
     }
 
     public void testLoadData() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final String HTML_CONTENT =
                 "<html><head><title>Hello,World!</title></head><body></body>" +
                 "</html>";
@@ -978,6 +1100,9 @@
 
     @UiThreadTest
     public void testLoadDataWithBaseUrl() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNull(mWebView.getUrl());
         String imgUrl = TestHtmlConstants.SMALL_IMG_URL; // relative
         // Snippet of HTML that will prevent favicon requests to the test server.
@@ -1063,6 +1188,9 @@
     }
 
     public void testFindAll()  throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Make the page scrollable, so we can detect the scrolling to make sure the
         // content fully loaded.
         mOnUiThread.setInitialScale(100);
@@ -1087,6 +1215,9 @@
     }
 
     public void testFindNext() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Reset the scaling so that finding the next "all" text will require scrolling.
         mOnUiThread.setInitialScale(100);
 
@@ -1143,6 +1274,9 @@
     }
 
     public void testDocumentHasImages() throws Exception, Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class DocumentHasImageCheckHandler extends Handler {
             private boolean mReceived;
             private int mMsgArg1;
@@ -1192,6 +1326,9 @@
     }
 
     public void testPageScroll() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
         int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
         String p = "<p style=\"height:" + dimension + "px;\">" +
@@ -1236,6 +1373,9 @@
     }
 
     public void testGetContentHeight() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mOnUiThread.loadDataAndWaitForCompletion(
                 "<html><body></body></html>", "text/html", null);
         new PollingCheck() {
@@ -1274,12 +1414,18 @@
 
     @UiThreadTest
     public void testPlatformNotifications() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         WebView.enablePlatformNotifications();
         WebView.disablePlatformNotifications();
     }
 
     @UiThreadTest
     public void testAccessPluginList() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         assertNotNull(WebView.getPluginList());
 
         // can not find a way to install plugins
@@ -1288,12 +1434,18 @@
 
     @UiThreadTest
     public void testDestroy() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Create a new WebView, since we cannot call destroy() on a view in the hierarchy
         WebView localWebView = new WebView(getActivity());
         localWebView.destroy();
     }
 
     public void testFlingScroll() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
         final int dimension = 10 * Math.max(metrics.widthPixels, metrics.heightPixels);
         String p = "<p style=\"height:" + dimension + "px;" +
@@ -1323,6 +1475,9 @@
     }
 
     public void testRequestFocusNodeHref() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         startWebServer(false);
         String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
@@ -1390,6 +1545,9 @@
     }
 
     public void testRequestImageRef() throws Exception, Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class ImageLoaded {
             public boolean mImageLoaded;
 
@@ -1470,10 +1628,16 @@
 
     @UiThreadTest
     public void testDebugDump() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mWebView.debugDump();
     }
 
     public void testGetHitTestResult() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final String anchor = "<p><a href=\"" + TestHtmlConstants.EXT_WEB_URL1
                 + "\">normal anchor</a></p>";
         final String blankAnchor = "<p><a href=\"\">blank anchor</a></p>";
@@ -1535,6 +1699,9 @@
     }
 
     public void testSetInitialScale() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final String p = "<p style=\"height:1000px;width:1000px\">Test setInitialScale.</p>";
         final float defaultScale =
             getInstrumentation().getTargetContext().getResources().getDisplayMetrics().density;
@@ -1586,6 +1753,9 @@
 
     @UiThreadTest
     public void testClearHistory() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         startWebServer(false);
         String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
@@ -1608,6 +1778,9 @@
 
     @UiThreadTest
     public void testSaveAndRestoreState() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // nothing to save
         assertNull(mWebView.saveState(new Bundle()));
 
@@ -1670,6 +1843,9 @@
     }
 
     public void testSetWebViewClient() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final ScaleChangedWebViewClient webViewClient = new ScaleChangedWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
         startWebServer(false);
@@ -1685,6 +1861,9 @@
 
     @UiThreadTest
     public void testInsecureSiteClearsCertificate() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class MockWebViewClient extends WaitForLoadedClient {
             public MockWebViewClient() {
                 super(mOnUiThread);
@@ -1713,6 +1892,9 @@
 
     @UiThreadTest
     public void testSecureSiteSetsCertificate() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class MockWebViewClient extends WaitForLoadedClient {
             public MockWebViewClient() {
                 super(mOnUiThread);
@@ -1741,6 +1923,9 @@
 
     @UiThreadTest
     public void testClearSslPreferences() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Load the first page. We expect a call to
         // WebViewClient.onReceivedSslError().
         final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient();
@@ -1768,6 +1953,9 @@
     }
 
     public void testOnReceivedSslError() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class MockWebViewClient extends WaitForLoadedClient {
             private String mErrorUrl;
             private WebView mWebView;
@@ -1801,6 +1989,9 @@
     }
 
     public void testOnReceivedSslErrorProceed() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class MockWebViewClient extends WaitForLoadedClient {
             public MockWebViewClient() {
                 super(mOnUiThread);
@@ -1819,6 +2010,9 @@
     }
 
     public void testOnReceivedSslErrorCancel() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class MockWebViewClient extends WaitForLoadedClient {
             public MockWebViewClient() {
                 super(mOnUiThread);
@@ -1838,6 +2032,9 @@
     }
 
     public void testSslErrorProceedResponseReusedForSameHost() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Load the first page. We expect a call to
         // WebViewClient.onReceivedSslError().
         final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient();
@@ -1858,6 +2055,9 @@
     }
 
     public void testSslErrorProceedResponseNotReusedForDifferentHost() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         // Load the first page. We expect a call to
         // WebViewClient.onReceivedSslError().
         final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient();
@@ -1910,6 +2110,9 @@
     }
 
     public void testRequestChildRectangleOnScreen() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
         final int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
         String p = "<p style=\"height:" + dimension + "px;width:" + dimension + "px\">&nbsp;</p>";
@@ -1933,6 +2136,10 @@
     }
 
     public void testSetDownloadListener() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+
         final CountDownLatch resultLatch = new CountDownLatch(1);
         final class MyDownloadListener implements DownloadListener {
             public String url;
@@ -1979,6 +2186,9 @@
 
     @UiThreadTest
     public void testSetLayoutParams() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(600, 800);
         mWebView.setLayoutParams(params);
         assertSame(params, mWebView.getLayoutParams());
@@ -1986,10 +2196,16 @@
 
     @UiThreadTest
     public void testSetMapTrackballToArrowKeys() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mWebView.setMapTrackballToArrowKeys(true);
     }
 
     public void testSetNetworkAvailable() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         WebSettings settings = mOnUiThread.getSettings();
         settings.setJavaScriptEnabled(true);
         startWebServer(false);
@@ -2020,6 +2236,9 @@
     }
 
     public void testSetWebChromeClient() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         final class MockWebChromeClient extends WaitForProgressClient {
             private boolean mOnProgressChanged = false;
 
@@ -2057,6 +2276,9 @@
     }
 
     public void testPauseResumeTimers() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         class Monitor {
             private boolean mIsUpdated;
 
@@ -2112,6 +2334,9 @@
 
     // verify query parameters can be passed correctly to android asset files
     public void testAndroidAssetQueryParam() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
 
         WebSettings settings = mOnUiThread.getSettings();
         settings.setJavaScriptEnabled(true);
@@ -2123,6 +2348,9 @@
 
     // verify anchors work correctly for android asset files
     public void testAndroidAssetAnchor() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
 
         WebSettings settings = mOnUiThread.getSettings();
         settings.setJavaScriptEnabled(true);
@@ -2133,6 +2361,9 @@
     }
 
     public void testEvaluateJavascript() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mOnUiThread.getSettings().setJavaScriptEnabled(true);
         mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
 
@@ -2156,6 +2387,9 @@
 
     // Verify Print feature can create a PDF file with a correct preamble.
     public void testPrinting() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         mOnUiThread.loadDataAndWaitForCompletion("<html><head></head>" +
                 "<body>foo</body></html>",
                 "text/html", null);
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
index dd784be..cb72ef0 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
@@ -31,6 +31,9 @@
 
     @UiThreadTest
     public void testAccessWebView() {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         WebView webView = getActivity().getWebView();
         WebViewTransport transport = webView.new WebViewTransport();
 
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
index 758afd7..b3c0915 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
@@ -23,6 +23,7 @@
 import android.view.InflateException;
 import android.view.View;
 import android.view.ViewGroup;
+import android.webkit.cts.NullWebViewUtils;
 import android.widget.RemoteViews;
 
 import com.android.cts.stub.R;
@@ -96,6 +97,9 @@
 
     @MediumTest
     public void testWebView() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
         RemoteViews orig = new RemoteViews(PACKAGE_NAME, R.layout.remote_view_test_bad_2);
         Parcel p = Parcel.obtain();
         orig.writeToParcel(p, 0);
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoActivity.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoActivity.java
index 4df8e62..ed82b08 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoActivity.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoActivity.java
@@ -106,6 +106,11 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
+        // Dismiss keyguard and keep screen on while this test is on.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
+                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
         super.onCreate(savedInstanceState);
         Window w = getWindow();
         w.setFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
diff --git a/tools/tradefed-host/res/report/cts_result.xsl b/tools/tradefed-host/res/report/cts_result.xsl
index 2d8bb50..fe49308 100644
--- a/tools/tradefed-host/res/report/cts_result.xsl
+++ b/tools/tradefed-host/res/report/cts_result.xsl
@@ -538,15 +538,7 @@
                                                             <xsl:value-of select="@result"/>
                                                         </div>
                                                     </TD>
-                                                    <TD class="failuredetails">
-                                                        <div class="details">
-                                                            <ul>
-                                                              <xsl:for-each select="Details/ValueArray/Value">
-                                                                <li><xsl:value-of select="."/></li>
-                                                              </xsl:for-each>
-                                                            </ul>
-                                                        </div>
-                                                    </TD>
+                                                    <TD class="failuredetails"/>
                                                 </xsl:if>
 
                                                 <xsl:if test="@result='fail'">
diff --git a/tools/vm-tests-tf/etc/starttests b/tools/vm-tests-tf/etc/starttests
index 0c8721b..be8fad4 100755
--- a/tools/vm-tests-tf/etc/starttests
+++ b/tools/vm-tests-tf/etc/starttests
@@ -181,7 +181,7 @@
                 depJar=`classnameToJar ${dep}`
                 classpath=${classpath}:${depJar}
             done
-            $valgrind $exe -Xint:$interpreter -Xmx512M -Xss32K -Xbootclasspath:$bpath $debug_opts \
+            $valgrind $exe -Xmx512M -Xss32K -Xbootclasspath:$bpath $debug_opts \
                 -classpath $dexcore:$classpath $mainclass >> $datadir/dalvikout 2>&1
 
             RESULTCODE=$?
diff --git a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
index d18ff4f..7f52edf 100644
--- a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
+++ b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
@@ -217,7 +217,7 @@
     }
 
     private String getShellExecJavaLine(String classpath, String mainclass) {
-      String cmd = String.format("ANDROID_DATA=%s dalvikvm -Xint:portable -Xmx512M -Xss32K " +
+      String cmd = String.format("ANDROID_DATA=%s dalvikvm -Xmx512M -Xss32K " +
               "-Djava.io.tmpdir=%s -classpath %s %s", TARGET_JAR_ROOT_PATH, TARGET_JAR_ROOT_PATH,
               classpath, mainclass);
       return "String res = getDevice().executeShellCommand(\""+ cmd + "\");\n" +