am fee56f1d: am c912a86c: am 00a871ca: am 4e2689b5: am d4fefc51: am 44e09b47: Merge "Add cts test for testing launcher version." into lmp-sprout-dev

* commit 'fee56f1dd004aa99e01393726cf2bf498143fc22':
  Add cts test for testing launcher version.
diff --git a/CtsBuild.mk b/CtsBuild.mk
index 1b12293..c745885 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -17,7 +17,7 @@
 # Functions to get the paths of the build outputs.
 
 define cts-get-lib-paths
-	$(foreach lib,$(1),$(HOST_OUT_JAVA_LIBRARIES)/$(lib).jar)
+	$(foreach lib,$(1),$(CTS_TESTCASES_OUT)/$(lib).jar)
 endef
 
 define cts-get-ui-lib-paths
@@ -25,7 +25,7 @@
 endef
 
 define cts-get-native-paths
-	$(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe),,,$(3))/$(exe)$(2))
+	$(foreach exe,$(1),$(CTS_TESTCASES_OUT)/$(exe)$(2))
 endef
 
 define cts-get-package-paths
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 2ef9b62..f382227 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -128,6 +128,7 @@
     CtsGraphicsTestCases \
     CtsGraphics2TestCases \
     CtsHardwareTestCases \
+    CtsJankTestCases \
     CtsJobSchedulerDeviceTestCases \
     CtsJniTestCases \
     CtsKeystoreTestCases \
@@ -203,11 +204,7 @@
     CtsUiAutomatorTests
 
 cts_device_jars := \
-    CtsDeviceJank \
-    CtsPrintInstrument
-
-cts_device_executables := \
-    print-instrument
+    CtsDeviceJank
 
 cts_target_junit_tests := \
     CtsJdwp
@@ -223,14 +220,8 @@
     $(call cts-get-ui-lib-paths,$(cts_ui_tests)) \
     $(call cts-get-ui-lib-paths,$(cts_device_jars)) \
     $(call cts-get-ui-lib-paths,$(cts_target_junit_tests)) \
-    $(call cts-get-executable-paths,$(cts_device_executables))
-
-# NOTE: If compiling on a 64 bit target, TARGET_2ND_ARCH will be non-empty
-# and will cause the function to expand to the secondary arch object
-# directory. If compiling on a 32 bit target, TARGET_2ND_ARCH will be
-# empty and will cause the function to expand to the primary arch object
-# directory.
-CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),32,$(TARGET_2ND_ARCH))
+    $(call cts-get-executable-paths,$(cts_device_executables)) \
+    $(call cts-get-native-paths,$(cts_native_tests),32)
 
 ifeq ($(TARGET_IS_64_BIT),true)
 CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),64)
diff --git a/apps/CameraITS/pymodules/its/caps.py b/apps/CameraITS/pymodules/its/caps.py
index 24f4e75..b97091b 100644
--- a/apps/CameraITS/pymodules/its/caps.py
+++ b/apps/CameraITS/pymodules/its/caps.py
@@ -222,6 +222,30 @@
     return props.has_key("android.control.aeCompensationRange") and \
            props["android.control.aeCompensationRange"] != [0, 0]
 
+def ae_lock(props):
+    """Returns whether a device supports AE lock
+
+    Args:
+        props: Camera properties object.
+
+    Return:
+        Boolean.
+    """
+    return props.has_key("android.control.aeLockAvailable") and \
+           props["android.control.aeLockAvailable"] == 1
+
+def awb_lock(props):
+    """Returns whether a device supports AWB lock
+
+    Args:
+        props: Camera properties object.
+
+    Return:
+        Boolean.
+    """
+    return props.has_key("android.control.awbLockAvailable") and \
+           props["android.control.awbLockAvailable"] == 1
+
 class __UnitTest(unittest.TestCase):
     """Run a suite of unit tests on this module.
     """
diff --git a/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py b/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
index 87500c7..6629df8 100644
--- a/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
+++ b/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
@@ -39,7 +39,8 @@
 
         # Capture at the smallest resolution.
         props = cam.get_camera_properties()
-        its.caps.skip_unless(its.caps.manual_sensor(props))
+        its.caps.skip_unless(its.caps.manual_sensor(props) and
+                             its.caps.awb_lock(props))
 
         _, fmt = its.objects.get_fastest_manual_capture_settings(props)
         w,h = fmt["width"], fmt["height"]
diff --git a/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py b/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
index 932c051..fa37174 100644
--- a/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
+++ b/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
@@ -15,6 +15,7 @@
 import its.image
 import its.device
 import its.objects
+import its.caps
 import os.path
 import numpy
 import pylab
@@ -41,6 +42,8 @@
 
         # Capture at full resolution.
         props = cam.get_camera_properties()
+        its.caps.skip_unless(its.caps.manual_sensor(props) and
+                             its.caps.awb_lock(props))
         w,h = its.objects.get_available_output_sizes("yuv", props)[0]
 
         # Converge 3A prior to capture.
diff --git a/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
index d09f2fd..e3755eb 100644
--- a/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
@@ -29,7 +29,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        its.caps.skip_unless(its.caps.ev_compensation(props))
+        its.caps.skip_unless(its.caps.ev_compensation(props) and
+                             its.caps.ae_lock(props))
 
         ev_per_step = its.objects.rational_to_float(
                 props['android.control.aeCompensationStep'])
diff --git a/apps/CameraITS/tests/scene1/test_locked_burst.py b/apps/CameraITS/tests/scene1/test_locked_burst.py
index 90662db..1dfe15f 100644
--- a/apps/CameraITS/tests/scene1/test_locked_burst.py
+++ b/apps/CameraITS/tests/scene1/test_locked_burst.py
@@ -15,6 +15,7 @@
 import its.image
 import its.device
 import its.objects
+import its.caps
 import os.path
 import numpy
 import pylab
@@ -36,6 +37,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
+        its.caps.skip_unless(its.caps.ae_lock(props) and
+                             its.caps.awb_lock(props))
 
         # Converge 3A prior to capture.
         cam.do_3a(do_af=True, lock_ae=True, lock_awb=True)
diff --git a/apps/CameraITS/tools/validate_scene.py b/apps/CameraITS/tools/validate_scene.py
index e1e89f2..ea851b7 100644
--- a/apps/CameraITS/tools/validate_scene.py
+++ b/apps/CameraITS/tools/validate_scene.py
@@ -16,6 +16,7 @@
 import its.device
 import its.objects
 import its.image
+import its.caps
 
 def main():
     """capture a yuv image and save it to argv[1]
@@ -39,8 +40,10 @@
         cam.do_3a(do_af=True, lock_ae=True, lock_awb=True)
         props = cam.get_camera_properties()
         req = its.objects.fastest_auto_capture_request(props)
-        req["android.control.awbLock"] = True
-        req["android.control.aeLock"] = True
+        if its.caps.ae_lock(props):
+            req["android.control.awbLock"] = True
+        if its.caps.awb_lock(props):
+            req["android.control.aeLock"] = True
         while True:
             print "Capture an image to check the test scene"
             cap = cam.do_capture(req)
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 87f962f..227c6cb 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -29,11 +29,12 @@
                                compatibility-common-util-devicesidelib_v2 \
                                cts-sensors-tests \
                                ctstestrunner \
+                               apache-commons-math \
+                               androidplot \
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 
-LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni \
-	#libcameraanalyzer # Needed for the disabled CameraAnalyzer tests
+LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index d0aa1ca..ca99a60 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
       android:versionCode="5"
-      android:versionName="5.1_r0.95">
+      android:versionName="5.0_r1.91">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
 
@@ -868,23 +868,6 @@
 
             <meta-data android:name="test_required_features" android:value="android.hardware.camera.any"/>
         </activity>
-<!-- Experimental. If re-enabling, libcameraanalyzer must be included in the build
-        <activity android:name=".camera.analyzer.CameraAnalyzerActivity"
-                 android:label="@string/camera_analyzer"
-                 android:screenOrientation="landscape">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/test_category_camera" />
-
-            <intent-filter>
-                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
-            </intent-filter>
-            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
-                android:resource="@xml/accessory_filter_adk" />
-        </activity>
--->
 
         <activity android:name=".camera.intents.CameraIntentsActivity"
                  android:label="@string/camera_intents">
@@ -1133,8 +1116,6 @@
             <meta-data android:name="test_category" android:value="@string/test_category_other" />
             <meta-data android:name="test_required_features"
                     android:value="android.software.app_widgets" />
-            <meta-data android:name="test_excluded_features"
-                       android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".deskclock.DeskClockTestsActivity"
@@ -1297,6 +1278,7 @@
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_QUERY" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_REMOVE" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
         </activity>
@@ -1432,6 +1414,17 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".audio.HifiUltrasoundTestActivity"
+                android:label="@string/hifi_ultrasound_test"
+                android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+        </activity>
+
         <service android:name=".tv.MockTvInputService"
             android:permission="android.permission.BIND_TV_INPUT">
             <intent-filter>
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/Android.mk b/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
deleted file mode 100644
index d595a20..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := libcameraanalyzer
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := com_android_cts_verifier_camera_analyzer_CameraTests.cpp \
-                com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp \
-                com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp \
-                com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp \
-                com_android_cts_verifier_camera_analyzer_MeteringTest.cpp \
-                com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
-
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include/colorchecker $(JNI_H_INCLUDE)
-
-LOCAL_CXX_STL := libc++
-LOCAL_STATIC_LIBRARIES := libcolorchecker
-LOCAL_SHARED_LIBRARIES := \
-    libjnigraphics \
-    libcutils \
-    libutils \
-    liblog \
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp
deleted file mode 100644
index fac39e1..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "AutoLockJNI"
-#include <utils/Log.h>
-#include "com_android_cts_verifier_camera_analyzer_AutoLockTest.h"
-
-#include <vector>
-#include <string>
-#include <string.h>
-
-#include "testingimage.h"
-#include "autolocktest.h"
-#include "vec2.h"
-#include "android/bitmap.h"
-
-jlong Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockTest(
-        JNIEnv*      env,
-        jobject      thiz) {
-
-    AutoLockTest* testHandler = new AutoLockTest();
-    long handlerAddress = (long)testHandler;
-    return handlerAddress;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockClass(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputImageAddress,
-        jlong        inputHandlerAddress,
-        jlong        checkercenterAddress,
-        jlong        checkerradiusAddress) {
-
-    ALOGV("JNI createAutoLockClass starts!");
-    long imageAddress = (long)inputImageAddress;
-    long handlerAddress = (long)inputHandlerAddress;
-
-    TestingImage *image = (TestingImage*) imageAddress;
-    AutoLockTest *testHandler = (AutoLockTest*) handlerAddress;
-
-    std::vector<std::vector< Vec2f > >* checkerCenter =
-            (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
-    std::vector<std::vector< float > >* checkerRadius =
-            (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
-    ALOGV("Classes recovered");
-
-    // Uses only the gray patches on the color checker for comparison.
-    testHandler->addDataToList(image->getColorChecker(3, 4, 0, 6,
-                                                      checkerCenter,
-                                                      checkerRadius));
-
-    delete image;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_processAutoLockTest(
-        JNIEnv*          env,
-        jobject          thiz,
-        jlong            inputHandlerAddress,
-        jbooleanArray    tempArray) {
-
-    ALOGV("Processing Auto Lock data!");
-
-    long handlerAddress = (long) inputHandlerAddress;
-    AutoLockTest *testHandler = (AutoLockTest*) handlerAddress;
-
-    testHandler->processData();
-
-    // Converts the native boolean array into a java boolean array.
-    const std::vector<bool>* nativeComparisonResults =
-            testHandler->getComparisonResults();
-    jboolean comparisonResults[nativeComparisonResults->size()];
-
-    for (int i = 0; i < nativeComparisonResults->size(); ++i) {
-        comparisonResults[i] = (jboolean) (*nativeComparisonResults)[i];
-    }
-
-    env->SetBooleanArrayRegion(tempArray,
-                               0, nativeComparisonResults->size(),
-                               comparisonResults);
-    testHandler->clearData();
-}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.h
deleted file mode 100644
index dc40bc2..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef JNI_CAMERAANALYZER_AUTOLOCKTEST_H
-#define JNI_CAMERAANALYZER_AUTOLOCKTEST_H
-
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockTest(
-        JNIEnv*      env,
-        jobject      thiz);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockClass(
-        JNIEnv *env,
-        jobject thiz,
-        jlong inputImageAddress,
-        jlong inputHandlerAddress,
-        jlong checkercenterAddress,
-        jlong checkerradiusAddress);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_processAutoLockTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress,
-        jbooleanArray    tempArray);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.cpp
deleted file mode 100644
index ed91233..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "CameraTestsJNI"
-#include <utils/Log.h>
-#include "com_android_cts_verifier_camera_analyzer_CameraTests.h"
-#include "android/bitmap.h"
-#include "testingimage.h"
-#include "imagetesthandler.h"
-
-#include <string.h>
-
-jlong Java_com_android_cts_verifier_camera_analyzer_CameraTests_findNative(
-        JNIEnv*      env,
-        jobject      thiz,
-        jobject      inputBitmap) {
-
-    ALOGV("JNI findNative starts!");
-
-    // Verify that we can handle the input bitmap
-    AndroidBitmapInfo inputInfo;
-    AndroidBitmap_getInfo(env, inputBitmap, &inputInfo);
-    if (inputInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888 &&
-        inputInfo.format != ANDROID_BITMAP_FORMAT_RGB_565) {
-        ALOGE("Only RGBA_8888 and RGB_565 bitmaps are supported, type was %d.",
-             inputInfo.format);
-    }
-
-    // Get some references to the fields and class type of ColorChecker
-    jclass thizCls = env->GetObjectClass(thiz);
-    ALOGV("ColorChecker field and classes reference finished!");
-
-    // Get raw inputs and outputs ready
-    uint8_t *inputBuffer = NULL;
-    int result = AndroidBitmap_lockPixels(
-            env,
-            inputBitmap,
-            reinterpret_cast<void**>(&inputBuffer));
-
-    if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
-        ALOGE("Unable to lock input bitmap");
-    }
-
-    uint8_t *outputImage = NULL;
-    int outputWidth, outputHeight;
-
-    ALOGV("Input and output images created!");
-
-    // Find the color checker
-    bool success;
-    uint8_t *inputBufferRGBA = NULL;
-    int inputStride;
-    bool freeInputRGBA = false;
-    switch (inputInfo.format) {
-        case ANDROID_BITMAP_FORMAT_RGB_565: {
-            // First convert to RGBA_8888
-            inputBufferRGBA = new uint8_t[inputInfo.width *
-                                          inputInfo.height *
-                                          4];
-            inputStride = inputInfo.width * 4;
-            uint8_t *outP = inputBufferRGBA;
-            for (int y = 0; y < inputInfo.height; y++ ) {
-                uint16_t *inP = (uint16_t*)(&inputBuffer[y * inputInfo.stride]);
-                for (int x = 0; x < inputInfo.width; x++) {
-                    *(outP++) = ( ((*inP) >> 0) & 0x001F) << 3;
-                    *(outP++) = ( ((*inP) >> 5) & 0x003F) << 2;
-                    *(outP++) = ( ((*inP) >> 11) & 0x001F) << 3;
-                    outP++;
-                    inP++;
-                }
-            }
-            freeInputRGBA = true;
-
-            ALOGV("RGB_565 Format with width, height and stride as %d, %d, %d",
-                 inputInfo.width, inputInfo.height, inputStride);
-            break;
-        }
-        case ANDROID_BITMAP_FORMAT_RGBA_8888: {
-            // Already in RGBA
-            inputBufferRGBA = inputBuffer;
-            inputStride = inputInfo.stride;
-            ALOGV("RGB_8888 Format with width, height and stride as %d, %d, %d",
-                 inputInfo.width, inputInfo.height, inputStride);
-            break;
-        }
-    }
-
-    TestingImage *input_testing_image =
-            new TestingImage(inputBufferRGBA, inputInfo.height, inputInfo.width,
-                             4, inputStride, 120, 160);
-
-    long lp = (long)input_testing_image;
-
-    result = AndroidBitmap_unlockPixels(env, inputBitmap);
-    if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
-        ALOGE("Unable to unlock input bitmap");
-    }
-
-    if (freeInputRGBA) {
-        ALOGV("Deleteing inputbufferRGBA");
-        delete[] inputBufferRGBA;
-    }
-
-    return lp;
-    ALOGV("Input format switched!");
-}
-
-jlong Java_com_android_cts_verifier_camera_analyzer_CameraTests_createImageTestHandler(
-        JNIEnv*      env,
-        jobject      thiz,
-        jint         debugHeight,
-        jint         debugWidth) {
-
-    ImageTestHandler* testHandler =
-            new ImageTestHandler(debugHeight, debugWidth);
-    long handlerAddress = (long)testHandler;
-    return handlerAddress;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_CameraTests_cleanUpHandler(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress) {
-
-    ImageTestHandler* testHandler = (ImageTestHandler*) (long) inputHandlerAddress;
-    delete testHandler;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_CameraTests_displayHandlerDebugOutput(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress) {
-
-    jclass thizCls = env->GetObjectClass(thiz);
-    jfieldID outputId = env->GetFieldID(thizCls, "mDebugOutput",
-                                        "Landroid/graphics/Bitmap;");
-
-    ImageTestHandler* testHandler = (ImageTestHandler*) (long) inputHandlerAddress;
-    uint8_t *outputImage =  new uint8_t[testHandler->getDebugHeight() *
-                                        testHandler->getDebugWidth() * 4];
-
-    const unsigned char *debugoutput = testHandler->debug_output();
-    memcpy(outputImage, debugoutput, testHandler->getDebugHeight() *
-            testHandler->getDebugWidth() * 4);
-
-    int outputWidth = testHandler->getDebugWidth();
-    int outputHeight = testHandler->getDebugHeight();
-    bool success = false;
-
-    if (outputImage == NULL) {
-        ALOGV("output Image is null!");
-    } else {
-        ALOGV("output Image is ready!");
-    }
-
-    // Create debug bitmap from output image data
-    if (outputImage != NULL) {
-        // Get method handles, create inputs to createBitmap
-        jclass bitmapClass =
-                env->FindClass("android/graphics/Bitmap");
-        jclass bitmapConfigClass =
-                env->FindClass("android/graphics/Bitmap$Config");
-
-        jmethodID createBitmap = env->GetStaticMethodID(
-            bitmapClass, "createBitmap",
-            "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
-
-        jmethodID getConfig = env->GetStaticMethodID(
-            bitmapConfigClass, "valueOf",
-            "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
-
-        // Create bitmap config and bitmap
-        jstring bitmapConfigValue = env->NewStringUTF("ARGB_8888");
-        jobject rgbaConfig = env->CallStaticObjectMethod(bitmapConfigClass,
-                                                         getConfig,
-                                                         bitmapConfigValue);
-        jobject outputBitmap = env->CallStaticObjectMethod(bitmapClass,
-                                                           createBitmap,
-                                                           outputWidth,
-                                                           outputHeight,
-                                                           rgbaConfig);
-        // Copy output image into it
-        uint8_t *outputBuffer;
-        int result = AndroidBitmap_lockPixels(
-                env,
-                outputBitmap,
-                reinterpret_cast<void**>(&outputBuffer) );
-
-        if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
-            ALOGE("Unable to lock output bitmap");
-        }
-
-        memcpy(outputBuffer, outputImage, outputWidth * outputHeight * 4);
-
-        result = AndroidBitmap_unlockPixels(env, outputBitmap);
-        if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
-            ALOGE("Unable to unlock output bitmap");
-        }
-
-        // Write new Bitmap reference into mDebugOutput class member
-        env->SetObjectField(thiz, outputId, outputBitmap);
-        ALOGV("Copied to outputBitmap");
-        delete [] outputImage;
-        env->DeleteLocalRef(outputBitmap);
-        env->DeleteLocalRef(rgbaConfig);
-        env->DeleteLocalRef(bitmapClass);
-        env->DeleteLocalRef(bitmapConfigClass);
-    }
-}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.h
deleted file mode 100644
index e071dc1..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef JNI_CAMERAANALYZER_CAMERATESTS_H
-#define JNI_CAMERAANALYZER_CAMERATESTS_H
-
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_CameraTests_findNative(
-        JNIEnv *env,
-        jobject thiz,
-        jobject inputBitmap);
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_CameraTests_createImageTestHandler(
-        JNIEnv*      env,
-        jobject      thiz,
-        jint         debugHeight,
-        jint         debugWidth);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_CameraTests_cleanUpHandler(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_CameraTests_displayHandlerDebugOutput(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp
deleted file mode 100644
index 94e3ac2..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "FindColorCheckerJNI"
-#include <utils/Log.h>
-#include "com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h"
-
-#include <string.h>
-#include "android/bitmap.h"
-#include "colorcheckertest.h"
-#include "testingimage.h"
-
-jlong Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jint         debugHeight,
-        jint         debugWidth) {
-    ColorCheckerTest* testHandler = new ColorCheckerTest(debugHeight,
-                                                         debugWidth);
-    long testHandlerAddress = (long)testHandler;
-    return testHandlerAddress;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerClass(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputImageAddress,
-        jlong        inputHandlerAddress) {
-    ALOGV("JNI createColorCheckerClass starts!");
-
-    TestingImage *testImage = (TestingImage*) (long) inputImageAddress;
-    ColorCheckerTest *testHandler = (ColorCheckerTest*)
-            (long) inputHandlerAddress;
-
-    testHandler->addTestingImage(testImage);
-}
-
-jboolean Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_processColorCheckerTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress) {
-
-    ColorCheckerTest *testHandler = (ColorCheckerTest*)
-            (long) inputHandlerAddress;
-    testHandler->processData();
-    return testHandler->getSuccess();
-}
-
-jlong Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerRadiusAdd(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress) {
-
-    ColorCheckerTest *testHandler = (ColorCheckerTest*)
-            (long) inputHandlerAddress;
-    long rtn = (long) testHandler->getCheckerRadiusAdd();
-    return rtn;
-}
-
-jlong Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerCenterAdd(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress) {
-
-    ColorCheckerTest *testHandler = (ColorCheckerTest*)
-            (long) inputHandlerAddress;
-
-    long rtn = (long) testHandler->getCheckerCenterAdd();
-    return rtn;
-}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h
deleted file mode 100644
index fb87735..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef JNI_CAMERAANALYZER_COLORCHECKERTEST_H
-#define JNI_CAMERAANALYZER_COLORCHECKERTEST_H
-
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerTest(
-    JNIEnv*      env,
-    jobject      thiz,
-    jint         output_height,
-    jint         output_width);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerClass(
-    JNIEnv *env,
-    jobject thiz,
-    jlong buffer_address,
-    jlong handler_address);
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerRadiusAdd(
-    JNIEnv *env,
-    jobject thiz,
-    jlong handler_address);
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerCenterAdd(
-    JNIEnv *env,
-    jobject thiz,
-    jlong handler_address);
-
-JNIEXPORT jboolean JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_processColorCheckerTest(
-    JNIEnv*      env,
-    jobject      thiz,
-    jlong        handler_address);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp
deleted file mode 100644
index 0224639..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "ExposureCompensationJNI"
-#include <utils/Log.h>
-#include <vector>
-#include <string.h>
-
-#include "android/bitmap.h"
-#include "testingimage.h"
-#include "exposurecompensationtest.h"
-#include "vec2.h"
-
-#include "com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h"
-
-jlong Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationTest(
-      JNIEnv*      env,
-      jobject      thiz,
-      jint         debugHeight,
-      jint         debugWidth) {
-
-    ExposureCompensationTest* testHandler =
-            new ExposureCompensationTest(debugHeight, debugWidth);
-    long handlerAddress = (long)testHandler;
-
-    return handlerAddress;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationClass(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputImageAddress,
-        jlong        inputHandlerAddress,
-        jlong        checkerCenterAddress,
-        jlong        checkerRadiusAddress,
-        jfloat       exposureValue) {
-
-    ALOGV("JNI createExposureCompensationClass starts!");
-
-    long imageAddress = (long)inputImageAddress;
-    long handlerAddress = (long)inputHandlerAddress;
-
-    TestingImage *inputImage = (TestingImage*) imageAddress;
-    ExposureCompensationTest *testHandler =
-            (ExposureCompensationTest*) handlerAddress;
-
-    std::vector<std::vector< Vec2f > >* checkerCenter =
-            (std::vector<std::vector< Vec2f > >*) (long) checkerCenterAddress;
-    std::vector<std::vector< float > >* checkerRadius =
-            (std::vector<std::vector< float > >*) (long) checkerRadiusAddress;
-
-    const std::vector<Vec3f>* checkerValue =
-            inputImage->getColorChecker(3, 4, 0, 6,
-                                        checkerCenter, checkerRadius);
-    testHandler->addDataToList((float) exposureValue, checkerValue);
-    delete inputImage;
-    delete checkerValue;
-}
-
-jstring Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_processExposureCompensationTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress) {
-
-    long handlerAddress = (long) inputHandlerAddress;
-    ExposureCompensationTest *testHandler =
-            (ExposureCompensationTest*) handlerAddress;
-
-    testHandler->processData();
-
-    const char* nativeDebugText = testHandler->getDebugText();
-    ALOGV("%s", nativeDebugText);
-    return env->NewStringUTF(nativeDebugText);
-}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h
deleted file mode 100644
index 8e8761d..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef JNI_CAMERAANALYZER_EXPOSURECOMPENSATIONTEST_H
-#define JNI_CAMERAANALYZER_EXPOSURECOMPENSATIONTEST_H
-
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jint         debugHeight,
-        jint         debugWidth);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationClass(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputImageAddress,
-        jlong        inputHandlerAddress,
-        jlong        checkerCenterAddress,
-        jlong        checkerRadiusAddress,
-        jfloat       exposureValue);
-
-
-JNIEXPORT jstring JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_processExposureCompensationTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputHandlerAddress);
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.cpp
deleted file mode 100644
index faebe21..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "MeteringJNI"
-#include <utils/Log.h>
-#include "com_android_cts_verifier_camera_analyzer_MeteringTest.h"
-
-#include <vector>
-#include <string>
-#include <string.h>
-#include <math.h>
-
-#include "testingimage.h"
-#include "meteringtest.h"
-#include "vec2.h"
-#include "android/bitmap.h"
-
-jlong Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringTest(
-        JNIEnv*      env,
-        jobject      thiz) {
-
-    MeteringTest* testHandler = new MeteringTest();
-    long handlerAddress = (long)testHandler;
-    return handlerAddress;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringClass(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputImageAddress,
-        jlong        inputHandlerAddress,
-        jlong        checkercenterAddress,
-        jlong        checkerradiusAddress){
-
-    ALOGV("JNI createMeteringClass starts!");
-    long imageAddress = (long)inputImageAddress;
-    long handlerAddress = (long)inputHandlerAddress;
-
-    TestingImage *image = (TestingImage*) imageAddress;
-    MeteringTest *testHandler = (MeteringTest*) handlerAddress;
-
-    std::vector<std::vector< Vec2f > >* checkerCenter =
-            (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
-    std::vector<std::vector< float > >* checkerRadius =
-            (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
-    ALOGV("Classes recovered");
-
-    testHandler->addDataToList(image->getColorChecker(3, 4, 0, 6,
-                                                      checkerCenter,
-                                                      checkerRadius));
-
-    delete image;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_MeteringTest_processMeteringTest(
-        JNIEnv*          env,
-        jobject          thiz,
-        jlong            inputHandlerAddress,
-        jbooleanArray    tempArray) {
-
-    ALOGV("Processing Auto Lock data!");
-
-    long handlerAddress = (long) inputHandlerAddress;
-    MeteringTest *testHandler = (MeteringTest*) handlerAddress;
-
-    testHandler->processData();
-
-    const std::vector<bool>* nativeComparisonResults =
-            testHandler->getComparisonResults();
-    jboolean jComparisonResults[nativeComparisonResults->size()];
-
-    for (int i = 0; i < nativeComparisonResults->size(); ++i) {
-        jComparisonResults[i] = (jboolean) (*nativeComparisonResults)[i];
-    }
-
-    env->SetBooleanArrayRegion(tempArray,
-                               0, nativeComparisonResults->size(),
-                               jComparisonResults);
-    testHandler->clearData();
-}
-
-// Find the gray checker borders from the native array of checker center and
-// radius. Convert the coordinate to the coordinates accepted by Android
-// Camera.Area type, which defines the top left corner to (-1000, -1000) and
-// bottom right corner to (1000, 1000).
-void Java_com_android_cts_verifier_camera_analyzer_MeteringTest_findGreyCoordinates(
-        JNIEnv*      env,
-        jobject      thiz,
-        jintArray    greyCoordinates,
-        jlong        checkercenterAddress,
-        jlong        checkerradiusAddress){
-
-    ALOGV("Start finding grey coordinates");
-
-    std::vector<std::vector< Vec2f > >* checkerCenter =
-            (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
-    std::vector<std::vector< float > >* checkerRadius =
-            (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
-
-    ALOGV("Checker recovered!");
-    int nativeGreyCoordinates[24];
-
-    for (int i = 0; i < 6; ++i) {
-        float radius = sqrt((*checkerRadius)[3][i]);
-        nativeGreyCoordinates[i * 4] = static_cast<int>(
-                ((*checkerCenter)[3][i].y() - radius)
-                / 160.0 * 2000.0 - 1000.0);
-        nativeGreyCoordinates[i * 4 + 1] = static_cast<int>(
-                ((*checkerCenter)[3][i].x() - radius)
-                / 120.0 * 2000.0 - 1000.0);
-        nativeGreyCoordinates[i * 4 + 2] = static_cast<int>(
-                ((*checkerCenter)[3][i].y() + radius)
-                / 160.0 * 2000.0 - 1000.0);
-        nativeGreyCoordinates[i * 4 + 3] = static_cast<int>(
-                ((*checkerCenter)[3][i].x() + radius)
-                / 120.0 * 2000.0 - 1000.0);
-
-        ALOGV("checker is bounded by %f, %f, %f",
-             (*checkerCenter)[3][i].x(), (*checkerCenter)[3][i].y(), radius);
-
-        ALOGV("Square is bounded by %d, %d, %d, %d",
-             nativeGreyCoordinates[i * 4], nativeGreyCoordinates[i * 4 + 1],
-             nativeGreyCoordinates[i * 4 + 2],
-             nativeGreyCoordinates[i * 4 + 3]);
-    }
-
-    env->SetIntArrayRegion(greyCoordinates, 0, 24, nativeGreyCoordinates);
-}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.h
deleted file mode 100644
index ecc1b96..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef JNI_CAMERAANALYZER_METERINGTEST_H
-#define JNI_CAMERAANALYZER_METERINGTEST_H
-
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringTest(
-        JNIEnv*      env,
-        jobject      thiz);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringClass(
-        JNIEnv *env,
-        jobject thiz,
-        jlong inputAddress,
-        jlong handlerAddress,
-        jlong checkercenterAddress,
-        jlong checkerradiusAddress);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_MeteringTest_processMeteringTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        handlerAddress,
-        jbooleanArray    tempArray);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_MeteringTest_findGreyCoordinates(
-        JNIEnv*      env,
-        jobject      thiz,
-        jintArray    greyCoordinates,
-        jlong        checkercenterAddress,
-        jlong        checkerradiusAddress);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
deleted file mode 100644
index bce0fca..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "WhiteBalanceJNI"
-#include <utils/Log.h>
-#include "com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h"
-
-#include <vector>
-#include <string>
-#include <string.h>
-
-#include "testingimage.h"
-#include "whitebalancetest.h"
-#include "vec2.h"
-#include "android/bitmap.h"
-
-jlong Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceTest(
-        JNIEnv*      env,
-        jobject      thiz) {
-
-    WhiteBalanceTest* testHandler = new WhiteBalanceTest();
-    long handlerAddress = (long)testHandler;
-    return handlerAddress;
-}
-
-void Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceClass(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        inputImageAddress,
-        jlong        inputHandlerAddress,
-        jlong        checkercenterAddress,
-        jlong        checkerradiusAddress,
-        jstring      whiteBalance){
-
-    ALOGV("JNI createWhiteBalanceClass starts!");
-    long imageAddress = (long)inputImageAddress;
-    long handlerAddress = (long)inputHandlerAddress;
-
-    TestingImage *image = (TestingImage*) imageAddress;
-    WhiteBalanceTest *testHandler = (WhiteBalanceTest*) handlerAddress;
-
-    std::vector<std::vector< Vec2f > >* checkerCenter =
-        (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
-    std::vector<std::vector< float > >* checkerRadius =
-        (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
-    ALOGV("Classes recovered");
-
-    jboolean isCopy;
-    const char* stringWhiteBalance =
-            env->GetStringUTFChars(whiteBalance, &isCopy);
-    ALOGV("White Balance is %s", stringWhiteBalance);
-
-    // Adds the gray checker's RGB values to the test handler.
-    testHandler->addDataToList(stringWhiteBalance,
-                               image->getColorChecker(3, 4, 0, 6,
-                                                      checkerCenter,
-                                                      checkerRadius));
-
-    env->ReleaseStringUTFChars(whiteBalance, stringWhiteBalance);
-    delete image;
-}
-
-jint Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_processWhiteBalanceTest(
-    JNIEnv*      env,
-    jobject      thiz,
-    jlong        inputHandlerAddress) {
-  ALOGV("Processing white balance test");
-
-  long handlerAddress = (long) inputHandlerAddress;
-  WhiteBalanceTest *testHandler = (WhiteBalanceTest*) handlerAddress;
-
-  testHandler->processData();
-
-  ALOGV("CCT is %d", testHandler->getCorrelatedColorTemp());
-  return testHandler->getCorrelatedColorTemp();
-}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h
deleted file mode 100644
index 88cf52e..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef JNI_CAMERAANALYZER_WHITEBALANCETEST_H
-#define JNI_CAMERAANALYZER_WHITEBALANCETEST_H
-
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jlong JNICALL
-Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceTest(
-        JNIEnv*      env,
-        jobject      thiz);
-
-JNIEXPORT void JNICALL
-Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceClass(
-        JNIEnv *env,
-        jobject thiz,
-        jlong inputAddress,
-        jlong handlerAddress,
-        jlong checkercenterAddress,
-        jlong checkerradiusAddress,
-        jstring whiteBalance);
-
-JNIEXPORT jint JNICALL
-Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_processWhiteBalanceTest(
-        JNIEnv*      env,
-        jobject      thiz,
-        jlong        handlerAddress);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/apps/CtsVerifier/lib/colorchecker/Android.mk b/apps/CtsVerifier/lib/colorchecker/Android.mk
deleted file mode 100644
index 48f1356..0000000
--- a/apps/CtsVerifier/lib/colorchecker/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-#####################
-# Build image analysis library
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := libcolorchecker
-
-LOCAL_SRC_FILES += testingimage.cpp \
-                   vec3.cpp \
-                   vec2.cpp \
-                   imagetesthandler.cpp \
-                   colorcheckertest.cpp \
-                   exposurecompensationtest.cpp \
-                   autolocktest.cpp \
-                   meteringtest.cpp \
-                   whitebalancetest.cpp
-
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include/colorchecker
-LOCAL_CXX_STL := libc++
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/apps/CtsVerifier/lib/colorchecker/autolocktest.cpp b/apps/CtsVerifier/lib/colorchecker/autolocktest.cpp
deleted file mode 100644
index 6bfa922..0000000
--- a/apps/CtsVerifier/lib/colorchecker/autolocktest.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "AutoLockTest"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <cmath>
-#include <string>
-
-#include "vec2.h"
-#include "vec3.h"
-#include "autolocktest.h"
-
-const float kOverExposure = 230.f;
-const float kEqThreshold = 0.05f;
-// Processes the color checker values and compare the two values from
-// the same individual test.
-void AutoLockTest::processData() {
-    ALOGV("Start Processing Auto Lock Test Data!");
-
-    int numTests = mCheckerColors.size() / 2;
-    mNumPatches = 0;
-
-    if (numTests > 0) {
-        mNumPatches = mCheckerColors[0].size();
-    }
-
-    for (int i = 0; i < numTests; ++i) {
-        mComparisonResults.push_back(
-                IsBrighterThan((&mCheckerColors[i * 2]),
-                               (&mCheckerColors[i * 2 + 1])));
-        mComparisonResults.push_back(
-                IsEquivalentTo((&mCheckerColors[i * 2]),
-                               (&mCheckerColors[i * 2 + 1])));
-    }
-}
-
-// Compares whether one array of gray color patches is brighter than
-// another one.
-bool AutoLockTest::IsBrighterThan(
-        const std::vector<Vec3f>* colorCheckers1,
-        const std::vector<Vec3f>* colorCheckers2) const {
-    float meanRatio = 0.f;
-    int meanNumCount = 0;
-
-    for (int i = 0; i < mNumPatches; ++i) {
-        float luminance1 = (*colorCheckers1)[i].convertToLuminance();
-        float luminance2 = (*colorCheckers2)[i].convertToLuminance();
-
-        // Consider a 5% raise as a considerably large increase.
-        if ((luminance1 < kOverExposure) && (luminance2 != 0.f)) {
-            meanRatio += luminance1 / luminance2;
-            ++meanNumCount;
-        }
-    }
-    meanRatio = meanRatio / meanNumCount;
-
-    return (meanRatio > 1 + kEqThreshold);
-}
-
-// Compares whether one array of gray color patches is within a small range
-// of the other one to be considered equivalent.
-bool AutoLockTest::IsEquivalentTo(
-        const std::vector<Vec3f>* colorCheckers1,
-        const std::vector<Vec3f>* colorCheckers2) const {
-    float meanRatio = 0.f;
-    int meanNumCount = 0;
-
-    for (int i = 0; i < mNumPatches; ++i) {
-        float luminance1 = (*colorCheckers1)[i].convertToLuminance();
-        float luminance2 = (*colorCheckers2)[i].convertToLuminance();
-        ALOGV("Luma_1 and Luma_2 is %f, %f", luminance1, luminance2);
-
-        if ((luminance1 < kOverExposure) && (luminance2 < kOverExposure)) {
-              meanRatio += luminance2 / luminance1;
-              ++meanNumCount;
-        }
-    }
-    meanRatio = meanRatio / meanNumCount;
-
-    return ((meanRatio >= 1 - kEqThreshold) && (meanRatio <= 1 + kEqThreshold));
-}
-
-void AutoLockTest::clearData() {
-    mCheckerColors.clear();
-    mComparisonResults.clear();
-}
diff --git a/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp b/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp
deleted file mode 100644
index ef7d2c6..0000000
--- a/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "ColorCheckerTest"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <cmath>
-#include <string>
-
-#include "vec2.h"
-#include "vec3.h"
-#include "colorcheckertest.h"
-
-const float GAMMA_CORRECTION = 2.2f;
-const float COLOR_ERROR_THRESHOLD = 200.f;
-ColorCheckerTest::~ColorCheckerTest() {
-    ALOGV("Deleting color checker test handler");
-
-    if (mImage != NULL) {
-        delete mImage;
-    }
-    ALOGV("Image deleted");
-
-    int numHorizontalLines = mCandidateColors.size();
-    int numVerticalLines = mCandidateColors[0].size();
-
-    for (int i = 0; i < numHorizontalLines; ++i) {
-        for (int j = 0; j < numVerticalLines; ++j) {
-            if (mCandidateColors[i][j] != NULL) {
-                delete mCandidateColors[i][j];
-            }
-            if (mCandidatePositions[i][j] != NULL) {
-                delete mCandidatePositions[i][j];
-            }
-        }
-    }
-    ALOGV("Candidates deleted!");
-
-    for (int i = 0; i < 4; ++i) {
-        for (int j = 0; j < 6; ++j) {
-            if (mMatchPositions[i][j] != NULL) {
-                delete mMatchPositions[i][j];
-            }
-            if (mReferenceColors[i][j] != NULL) {
-                delete mReferenceColors[i][j];
-            }
-            if (mMatchColors[i][j] != NULL) {
-                delete mMatchColors[i][j];
-            }
-        }
-    }
-}
-
-// Adds a new image to the test handler.
-void ColorCheckerTest::addTestingImage(TestingImage* inputImage) {
-    if (mImage != NULL) {
-        delete mImage;
-    }
-    mImage = NULL;
-    ALOGV("Original image deleted");
-    mImage = inputImage;
-
-    if ((mImage->getHeight() == getDebugHeight()) &&
-        (mImage->getWidth() == getDebugWidth())) {
-        copyDebugImage(getDebugHeight(), getDebugWidth(), mImage->getImage());
-    }
-}
-
-void ColorCheckerTest::processData() {
-    mSuccess = false;
-    initializeRefColor();
-    edgeDetection();
-}
-
-void ColorCheckerTest::initializeRefColor() {
-    mReferenceColors.resize(4, std::vector<Vec3i*>(6, NULL));
-    mMatchPositions.resize(4, std::vector<Vec2f*>(6, NULL));
-    mMatchColors.resize(4, std::vector<Vec3f*>(6, NULL));
-    mMatchRadius.resize(4, std::vector<float>(6, 0.f));
-
-    mReferenceColors[0][0]= new Vec3i(115, 82, 68);
-    mReferenceColors[0][1]= new Vec3i(194, 150, 130);
-    mReferenceColors[0][2]= new Vec3i(98, 122, 157);
-    mReferenceColors[0][3]= new Vec3i(87, 108, 67);
-    mReferenceColors[0][4]= new Vec3i(133, 128, 177);
-    mReferenceColors[0][5]= new Vec3i(103, 189, 170);
-    mReferenceColors[1][0]= new Vec3i(214, 126, 44);
-    mReferenceColors[1][1]= new Vec3i(80, 91, 166);
-    mReferenceColors[1][2]= new Vec3i(193, 90, 99);
-    mReferenceColors[1][3]= new Vec3i(94,  60, 108);
-    mReferenceColors[1][4]= new Vec3i(157, 188, 64);
-    mReferenceColors[1][5]= new Vec3i(224, 163, 46);
-    mReferenceColors[2][0]= new Vec3i(56, 61, 150);
-    mReferenceColors[2][1]= new Vec3i(70, 148, 73);
-    mReferenceColors[2][2]= new Vec3i(175, 54, 60);
-    mReferenceColors[2][3]= new Vec3i(231, 199, 31);
-    mReferenceColors[2][4]= new Vec3i(187, 86, 149);
-    mReferenceColors[2][5]= new Vec3i(8, 133, 161);
-    mReferenceColors[3][0]= new Vec3i(243, 243, 242);
-    mReferenceColors[3][1]= new Vec3i(200, 200, 200);
-    mReferenceColors[3][2]= new Vec3i(160, 160, 160);
-    mReferenceColors[3][3]= new Vec3i(122, 122, 121);
-    mReferenceColors[3][4]= new Vec3i(85, 85, 85);
-    mReferenceColors[3][5]= new Vec3i(52, 52, 52);
-}
-
-void ColorCheckerTest::edgeDetection() {
-    int width = mImage->getWidth();
-    int height = mImage->getHeight();
-
-    bool* edgeMap = new bool[height * width];
-    unsigned char* grayImage = new unsigned char[height * width];
-
-    // If the image is a color image and can be converted to a luminance layer
-    if (mImage->rgbToGrayScale(grayImage)) {
-        float* gradientMap = new float[height * width * 2];
-
-        // Computes the gradient image on the luminance layer.
-        computeGradient(grayImage, gradientMap);
-
-        float* gradientMagnitude = new float[height * width];
-        int* gradientDirectionInt = new int[height * width];
-        float* gradientDirection = new float[height * width];
-
-        // Computes the absolute gradient of the image without padding.
-        for (int i = 1; i < height - 1; ++i) {
-            for (int j = 1; j < width - 1; ++j) {
-                gradientMagnitude[i * width + j] =
-                        sqrt(gradientMap[(i * width + j) * 2] *
-                             gradientMap[(i * width + j) * 2] +
-                             gradientMap[(i * width + j ) * 2 + 1] *
-                             gradientMap[(i * width + j ) * 2 + 1]);
-
-                // Computes the gradient direction of the image.
-                if (gradientMap[(i * width + j) * 2] == 0 ) {
-                    // If the vertical gradient is 0, the edge is horizontal
-                    // Mark the gradient direction as 90 degrees.
-                    gradientDirectionInt[i * width + j] = 2;
-                    gradientDirection[i * width + j] = 90.0f;
-                } else {
-                    // Otherwise the atan operation is valid and can decide
-                    // the gradient direction of the edge.
-                    float gradient = atan(gradientMap[(i * width + j) * 2 + 1]
-                            / gradientMap[(i * width + j) * 2])
-                            / (M_PI / 4);
-
-                    gradientDirection[i * width + j] = gradient * 45.0f;
-
-                    // Maps the gradient direction to 4 major directions with
-                    // 0 mapped to up and 2 mapped to right.
-                    if (gradient - floor(gradient) > 0.5) {
-                        gradientDirectionInt[i * width + j] =
-                                (static_cast<int>(ceil(gradient)) + 4) % 4;
-                    } else {
-                        gradientDirectionInt[i * width + j] =
-                                (static_cast<int>(floor(gradient)) + 4) % 4;
-                    }
-                }
-            }
-        }
-
-        // Compute a boolean map to show whether a pixel is on the edge.
-        for (int i = 1; i < height - 1; ++i) {
-            for (int j = 1; j < width - 1; ++j) {
-                edgeMap[i * width + j] = false;
-
-                switch (gradientDirectionInt[i * width + j]) {
-                    case 0:
-                        // If the gradient points rightwards, the pixel is
-                        // on an edge if it has a larger absolute gradient than
-                        // pixels on its left and right sides.
-                        if ((gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[i * width + j + 1]) &&
-                            (gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[i * width + j - 1])) {
-                            edgeMap[i * width + j] = true;
-                        }
-                        break;
-                    case 1:
-                        // If the gradient points right-downwards, the pixel is
-                        // on an edge if it has a larger absolute gradient than
-                        // pixels on its upper left and bottom right sides.
-                        if ((gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[(i + 1) * width + j + 1]) &&
-                            (gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[(i - 1) * width + j - 1])) {
-                            edgeMap[i * width + j] = true;
-                        }
-                        break;
-                    case 2:
-                        // If the gradient points upwards, the pixel is
-                        // on an edge if it has a larger absolute gradient than
-                        // pixels on its up and down sides.
-                        if ((gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[(i + 1) * width + j]) &&
-                            (gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[(i - 1) * width + j])) {
-                            edgeMap[i * width + j] = true;
-                        }
-                        break;
-                    case 3:
-                        // If the gradient points right-upwards, the pixel is
-                        // on an edge if it has a larger absolute gradient than
-                        // pixels on its bottom left and upper right sides.
-                        if ((gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[(i - 1) * width + j + 1]) &&
-                            (gradientMagnitude[i * width + j] >=
-                                gradientMagnitude[(i + 1) * width + j - 1])) {
-                            edgeMap[i * width + j] = true;
-                        }
-                  }
-
-             }
-        }
-
-        houghLineDetection(edgeMap, gradientMagnitude, gradientDirection);
-
-        // Cleans up
-        delete[] gradientMap;
-        delete[] gradientDirectionInt;
-        delete[] gradientMagnitude;
-        delete[] gradientDirection;
-
-    } else {
-        ALOGE("Not a color image!");
-    }
-
-    delete[] edgeMap;
-    delete[] grayImage;
-}
-
-// Runs the hough voting algorithm to find the grid of the color checker
-// with the edge map, gradient direction and gradient magnitude as inputs.
-void ColorCheckerTest::houghLineDetection(bool* edgeMap,
-                                          float* gradientMagnitude,
-                                          float* gradientDirection) {
-    // Constructs a graph for Hough voting. The vertical axis counts the vote
-    // for a certain angle. The horizontal axis counts the vote for the distance
-    // of a line from the origin of the image.
-    int houghHeight = 180;
-    int houghWidth = 200;
-    int houghCounts[houghHeight][houghWidth];
-    int houghSum[houghHeight][houghWidth];
-
-    int** houghVote;
-    houghVote = new int*[180];
-    for (int i = 0; i < 180; ++i) {
-        houghVote[i] = new int[200];
-    }
-
-    for (int i = 0; i < houghHeight; ++i) {
-        for (int j = 0; j < houghWidth; ++j) {
-            houghCounts[i][j] = 0;
-            houghVote[i][j] = 0;
-            houghSum[i][j] = 0;
-        }
-    }
-
-    // Vectors to record lines in two orthogonal directions.
-    // Each line is represented by its direction and its distance to the origin.
-    std::vector<std::vector<int> > verticalLines;
-    std::vector<std::vector<int> > horizontalLines;
-    float radius;
-    int height = mImage->getHeight();
-    int width = mImage->getWidth();
-
-    // Processes the signicant edge pixels and cast vote for the corresponding
-    // edge passing this pixel.
-    for (int i = 1; i < height - 1; ++i) {
-        for (int j = 1; j < width - 1; ++j) {
-            // Sets threashold for the gradient magnitude to discount noises
-            if (edgeMap[i * width + j] &&
-                (gradientMagnitude[i * width + j] > 15)) {
-                int shiftedAngle;
-
-                // Shifts angles for 45 degrees so the vertical and horizontal
-                // direction is mapped to 45 and 135 degrees to avoid padding.
-                // This uses the assumption that the color checker is placed
-                // roughly parallel to the image boarders. So that the edges
-                // at the angle of 45 will be rare.
-                shiftedAngle = (static_cast<int>(
-                        -gradientDirection[i * width + j]) + 225 % 180);
-                float shiftedAngleRad = static_cast<float>(shiftedAngle)
-                        * M_PI / 180.0f;
-
-                // Computes the distance of the line from the origin.
-                float a, b;
-                a = static_cast<float>(i - j) / sqrt(2.0f);
-                b = static_cast<float>(i + j) / sqrt(2.0f);
-                radius = a * sin(shiftedAngleRad) - b * cos(shiftedAngleRad);
-
-                // Adds one vote for the line. The line's angle is shifted by
-                // 45 degrees to avoid avoid padding for the vertical lines,
-                // which is more common than diagonal lines. The line's
-                // distance is mapped to [0, 200] from [-200, 200].
-                ++houghCounts[shiftedAngle][static_cast<int>((radius / 2.0f) +
-                                                              100.0f)];
-
-                drawPoint(i, j, Vec3i(255, 255, 255));
-            }
-        }
-    }
-
-    int houghAngleSum[houghHeight];
-    int primaryVerticalAngle, primaryHorizontalAngle;
-    int max1 = 0;
-    int max2 = 0;
-
-    // Looking for the two primary angles of the lines.
-    for (int i = 5; i < houghHeight - 5; ++i) {
-        houghAngleSum[i] = 0;
-        for (int j = 0; j < houghWidth; ++j) {
-            for (int l = -5; l <= 5; ++l) {
-                houghSum[i][j] += houghCounts[i + l][j];
-            }
-            houghAngleSum[i] += houghSum[i][j];
-        }
-
-        if ((i < houghHeight / 2) && (houghAngleSum[i] > max1)) {
-            max1 = houghAngleSum[i];
-            primaryVerticalAngle = i;
-        } else if ((i > houghHeight / 2) && (houghAngleSum[i] > max2)) {
-            max2 = houghAngleSum[i];
-            primaryHorizontalAngle = i;
-        }
-    }
-
-    ALOGV("Primary angles are %d, %d",
-         primaryVerticalAngle, primaryHorizontalAngle);
-
-    int angle;
-
-    // For each primary angle, look for the highest voted lines.
-    for (int k = 0; k < 2; ++k) {
-        if (k == 0) {
-            angle = primaryVerticalAngle;
-        } else {
-            angle = primaryHorizontalAngle;
-        }
-
-        std::vector<int> line(2);
-        for (int j = 2; j < houghWidth - 2; ++j) {
-            houghVote[angle][j] = houghSum[angle][j];
-            houghSum[angle][j] = 0;
-        }
-
-        // For each radius, average the vote with nearby ones.
-        for (int j = 2; j < houghWidth - 2; ++j) {
-            for (int m = -2; m <= 2; ++m) {
-                houghSum[angle][j] += houghVote[angle][j + m];
-            }
-        }
-
-        bool isCandidate[houghWidth];
-
-        // Find whether a lines is a candidate by rejecting the ones that have
-        // lower vote than others in the neighborhood.
-        for (int j = 2; j < houghWidth - 2; ++j) {
-            isCandidate[j] = true;
-            for (int m = -2; ((isCandidate[j]) && (m <= 2)); ++m) {
-                if ((houghSum[angle][j] < 20) ||
-                    (houghSum[angle][j] < houghSum[angle][j + m])) {
-                    isCandidate[j] = false;
-                }
-            }
-        }
-
-        int iter1 = 0;
-        int iter2 = 0;
-        int count = 0;
-
-        // Finds the lines that are not too close to each other and add to the
-        // detected lines.
-        while (iter2 < houghWidth) {
-            while ((!isCandidate[iter2]) && (iter2 < houghWidth)) {
-                ++iter2;
-            }
-            if ((isCandidate[iter2]) && (iter2 - iter1 < 5)) {
-                iter1 = (iter2 + iter1) / 2;
-                ++iter2;
-            } else {
-                line[0] = angle;
-                line[1] = (iter1 - 100) * 2;
-                if (iter1 != 0) {
-                    if (k == 0) {
-                        verticalLines.push_back(line);
-                        Vec3i color(verticalLines.size() * 20, 0, 0);
-                        drawLine(line[0], line[1], color);
-                    } else {
-                        horizontalLines.push_back(line);
-                        Vec3i color(0, horizontalLines.size() * 20, 0);
-                        drawLine(line[0], line[1], color);
-                    }
-                }
-                iter1 = iter2;
-                ++iter2;
-                ALOGV("pushing back line %d %d", line[0], line[1]);
-            }
-        }
-    }
-
-    ALOGV("Numbers of lines in each direction is %d, %d",
-         verticalLines.size(), horizontalLines.size());
-
-    for (int i = 0; i < 180; ++i) {
-        delete[] houghVote[i];
-    }
-    delete[] houghVote;
-
-    findCheckerBoards(verticalLines, horizontalLines);
-}
-
-// Computes the gradient in both x and y direction of a layer
-void ColorCheckerTest::computeGradient(unsigned char* layer,
-                                       float* gradientMap) {
-    int width = mImage->getWidth();
-    int height = mImage->getHeight();
-
-    // Computes the gradient in the whole image except the image boarders.
-    for (int i = 1; i < height - 1; ++i) {
-        for (int j = 1; j < width - 1; ++j) {
-            gradientMap[(i * width + j) * 2] =
-                    0.5f * (layer[i * width + j + 1] -
-                            layer[i * width + j - 1]);
-            gradientMap[(i * width + j) * 2 + 1] =
-                    0.5f * (layer[(i + 1) * width + j] -
-                           layer[(i - 1) * width + j]);
-        }
-    }
-}
-
-// Tries to find the checker boards with the highest voted lines
-void ColorCheckerTest::findCheckerBoards(
-        std::vector<std::vector<int> > verticalLines,
-        std::vector<std::vector<int> > horizontalLines) {
-    ALOGV("Start looking for Color checker");
-
-    int numHorizontalLines = mCandidateColors.size();
-    int numVerticalLines;
-    if (numHorizontalLines > 0) {
-        numVerticalLines = mCandidateColors[0].size();
-        for (int i = 0; i < numHorizontalLines; ++i) {
-            for (int j = 0; j < numVerticalLines; ++j) {
-                if (mCandidateColors[i][j] != NULL) {
-                    delete mCandidateColors[i][j];
-                }
-                if (mCandidatePositions[i][j] != NULL) {
-                    delete mCandidatePositions[i][j];
-                }
-            }
-            mCandidateColors[i].clear();
-            mCandidatePositions[i].clear();
-        }
-    }
-    mCandidateColors.clear();
-    mCandidatePositions.clear();
-
-    ALOGV("Candidates deleted!");
-
-    numVerticalLines = verticalLines.size();
-    numHorizontalLines = horizontalLines.size();
-    Vec2f pointUpperLeft;
-    Vec2f pointBottomRight;
-
-    mCandidateColors.resize(numHorizontalLines - 1);
-    mCandidatePositions.resize(numHorizontalLines - 1);
-
-    for (int i = numVerticalLines - 1; i >= 1; --i) {
-        for (int j = 0; j < numHorizontalLines - 1; ++j) {
-            // Finds the upper left and bottom right corner of each rectangle
-            // formed by two neighboring highest voted lines.
-            pointUpperLeft = findCrossing(verticalLines[i], horizontalLines[j]);
-            pointBottomRight = findCrossing(verticalLines[i - 1],
-                                            horizontalLines[j + 1]);
-
-            Vec3i* color = new Vec3i();
-            Vec2f* pointCenter = new Vec2f();
-            // Verifies if they are separated by a reasonable distance.
-            if (verifyPointPair(pointUpperLeft, pointBottomRight,
-                                pointCenter, color)) {
-                mCandidatePositions[j].push_back(pointCenter);
-                mCandidateColors[j].push_back(color);
-                ALOGV("Color at (%d, %d) is (%d, %d, %d)", j, i,color->r(), color->g(), color->b());
-
-            } else {
-                mCandidatePositions[j].push_back(NULL);
-                mCandidateColors[j].push_back(NULL);
-                delete color;
-                delete pointCenter;
-            }
-        }
-    }
-
-    ALOGV("Candidates Number (%d, %d)", mCandidateColors.size(), mCandidateColors[0].size());
-    // Verifies whether the current line candidates form a valid color checker.
-    verifyColorGrid();
-}
-
-// Returns the corssing point of two lines given the lines.
-Vec2f ColorCheckerTest::findCrossing(std::vector<int> line1,
-                                     std::vector<int> line2) {
-    Vec2f crossingPoint;
-    float r1 = static_cast<float>(line1[1]);
-    float r2 = static_cast<float>(line2[1]);
-    float ang1, ang2;
-    float y1, y2;
-
-    ang1 = static_cast<float>(line1[0]) / 180.0f * M_PI;
-    ang2 = static_cast<float>(line2[0]) / 180.0f * M_PI;
-
-    float x, y;
-    x = (r1 * cos(ang2) - r2 * cos(ang1)) / sin(ang1 - ang2);
-    y = (r1 * sin(ang2) - r2 * sin(ang1)) / sin(ang1 - ang2);
-
-    crossingPoint.set((x + y) / sqrt(2.0), (y - x) / sqrt(2.0));
-
-    //ALOGV("Crosspoint at (%f, %f)", crossingPoint.x(), crossingPoint.y());
-    return crossingPoint;
-}
-
-// Verifies whether two opposite corners on a quadrilateral actually can be
-// the two corners of a color checker.
-bool ColorCheckerTest::verifyPointPair(Vec2f pointUpperLeft,
-                                       Vec2f pointBottomRight,
-                                       Vec2f* pointCenter,
-                                       Vec3i* color) {
-    bool success = true;
-
-    /** 5 and 30 are the threshold tuned for resolution 640*480*/
-    if ((pointUpperLeft.x() < 0) ||
-        (pointUpperLeft.x() >= mImage->getHeight()) ||
-        (pointUpperLeft.y() < 0) ||
-        (pointUpperLeft.y() >= mImage->getWidth()) ||
-        (pointBottomRight.x() < 0) ||
-        (pointBottomRight.x() >= mImage->getHeight()) ||
-        (pointBottomRight.y() < 0) ||
-        (pointBottomRight.y() >= mImage->getWidth()) ||
-        (std::abs(pointUpperLeft.x() - pointBottomRight.x()) <= 5) ||
-        (std::abs(pointUpperLeft.y() - pointBottomRight.y()) <= 5) ||
-        (std::abs(pointUpperLeft.x() - pointBottomRight.x()) >= 30) ||
-        (std::abs(pointUpperLeft.y() - pointBottomRight.y()) >= 30)) {
-
-        // If any of the quadrilateral corners are out of the image or if
-        // the distance between them are too large or too big, the quadrilateral
-        // could not be one of the checkers
-        success = false;
-    } else {
-        // Find the checker center if the corners of the rectangle meet criteria
-        pointCenter->set((pointUpperLeft.x() + pointBottomRight.x()) / 2.0f,
-                       (pointUpperLeft.y() + pointBottomRight.y()) / 2.0f);
-        color->set(mImage->getPixelValue(*pointCenter).r(),
-                   mImage->getPixelValue(*pointCenter).g(),
-                   mImage->getPixelValue(*pointCenter).b());
-        ALOGV("Color at (%f, %f) is (%d, %d, %d)", pointCenter->x(), pointCenter->y(),color->r(), color->g(), color->b());
-    }
-    return success;
-}
-
-// Verifies the color checker centers and finds the match between the detected
-// color checker and the reference MacBeth color checker
-void ColorCheckerTest::verifyColorGrid() {
-    ALOGV("Start looking for Color Grid");
-    int numHorizontalLines = mCandidateColors.size();
-    int numVerticalLines = mCandidateColors[0].size();
-    bool success = false;
-
-    // Computes the standard deviation of one row/column of the proposed color
-    // checker. Discards the row/column if the std is below a threshold.
-    for (int i = 0; i < numHorizontalLines; ++i) {
-        Vec3f meanColor(0.f, 0.f, 0.f);
-        int numNonZero = 0;
-
-        for (int j = 0; j < numVerticalLines; ++j) {
-            if (mCandidateColors[i][j] != NULL) {
-                ALOGV("candidate color (%d, %d) is (%d, %d, %d)", i, j, mCandidateColors[i][j]->r(), mCandidateColors[i][j]->g(), mCandidateColors[i][j]->b());
-
-                meanColor = meanColor + (*mCandidateColors[i][j]);
-                ++numNonZero;
-            }
-        }
-        if (numNonZero > 0) {
-            meanColor = meanColor / numNonZero;
-        }
-        ALOGV("Mean color for vertical direction computed!");
-
-        float std = 0;
-        for (int j = 0; j < numVerticalLines; ++j) {
-            if (mCandidateColors[i][j] != NULL) {
-                std += mCandidateColors[i][j]->squareDistance<float>(meanColor);
-            }
-        }
-        if (numNonZero > 0) {
-            std = sqrt(std / (3 * numNonZero));
-        }
-        ALOGV("st. deviation for the %d dir1 is %d", i, static_cast<int>(std));
-
-        if ((std <= 30) && (numNonZero > 1)) {
-            for (int j = 0; j < numVerticalLines; ++j) {
-                if (mCandidateColors[i][j] != NULL) {
-                    delete mCandidateColors[i][j];
-                    mCandidateColors[i][j] = NULL;
-                }
-            }
-        }
-    }
-
-    // Discards the column/row of the color checker if the std is below a
-    // threshold.
-    for (int j = 0; j < numVerticalLines; ++j) {
-        Vec3f meanColor(0.f, 0.f, 0.f);
-        int numNonZero = 0;
-
-        for (int i = 0; i < numHorizontalLines; ++i) {
-            if (mCandidateColors[i][j] != NULL) {
-                meanColor = meanColor + (*mCandidateColors[i][j]);
-                ++numNonZero;
-            }
-        }
-        if (numNonZero > 0) {
-            meanColor = meanColor / numNonZero;
-        }
-
-        float std = 0;
-        for (int i = 0; i < numHorizontalLines; ++i) {
-            if (mCandidateColors[i][j] != NULL) {
-                std += mCandidateColors[i][j]->squareDistance<float>(meanColor);
-            }
-        }
-        if (numNonZero > 0) {
-            std = sqrt(std / (3 * numNonZero));
-        }
-
-        ALOGV("st. deviation for the %d dir2 is %d", j, static_cast<int>(std));
-
-        if ((std <= 30) && (numNonZero > 1)) {
-            for (int i = 0; i < numHorizontalLines; ++i) {
-                if (mCandidateColors[i][j] != NULL) {
-                    delete mCandidateColors[i][j];
-                    mCandidateColors[i][j] = NULL;
-                }
-            }
-        }
-    }
-
-    for (int i = 0; i < numHorizontalLines; ++i) {
-        for (int j = 0; j < numVerticalLines; ++j) {
-            if (mCandidateColors[i][j] != NULL) {
-                ALOGV("position (%d, %d) is at (%f, %f) with color (%d, %d, %d)",
-                     i, j,
-                     mCandidatePositions[i][j]->x(),
-                     mCandidatePositions[i][j]->y(),
-                     mCandidateColors[i][j]->r(),
-                     mCandidateColors[i][j]->g(),
-                     mCandidateColors[i][j]->b());
-            } else {
-                ALOGV("position (%d, %d) is 0", i, j);
-            }
-        }
-    }
-
-    // Finds the match between the detected color checker and the reference
-    // MacBeth color checker.
-    int rowStart = 0;
-    int rowEnd = 0;
-
-    // Loops until all dectected color checker has been processed.
-    while (!success) {
-        int columnStart = 0;
-        int columnEnd = 0;
-        bool isRowStart = false;
-        bool isRowEnd = true;
-
-        // Finds the row start of the next block of detected color checkers.
-        while ((!isRowStart) && (rowStart <  numHorizontalLines)) {
-            for (int j = 0; j < numVerticalLines; ++j) {
-                if (mCandidateColors[rowStart][j] != NULL) {
-                    isRowStart = true;
-                }
-            }
-            ++rowStart;
-        }
-        rowStart--;
-        rowEnd = rowStart;
-        ALOGV("rowStart is %d", rowStart);
-
-        // Finds the row end of the next block of detected color checkers.
-        while ((isRowEnd) && (rowEnd < numHorizontalLines)) {
-            isRowEnd = false;
-            for (int j = 0; j < numVerticalLines; ++j) {
-                if (mCandidateColors[rowEnd][j] != NULL) {
-                    isRowEnd= true;
-                }
-            }
-            if (isRowEnd) {
-                ++rowEnd;
-            }
-        }
-        if ((!isRowEnd) && isRowStart) {
-            rowEnd--;
-        }
-        if ((isRowEnd) && (rowEnd == numHorizontalLines)) {
-            rowEnd--;
-            isRowEnd = false;
-        }
-        ALOGV("rowEnd is %d", rowEnd);
-
-        // Matches color checkers between the start row and the end row.
-        bool successVertical = false;
-
-        while (!successVertical) {
-            bool isColumnEnd = true;
-            bool isColumnStart = false;
-
-            // Finds the start column of the next block of color checker
-            while ((!isColumnStart) && (columnStart < numVerticalLines)) {
-                if (mCandidateColors[rowStart][columnStart] != NULL) {
-                    isColumnStart = true;
-                }
-                ++columnStart;
-            }
-            columnStart--;
-            columnEnd = columnStart;
-
-            // Finds the end column of the next block of color checker
-            while ((isColumnEnd) && (columnEnd < numVerticalLines)) {
-                isColumnEnd = false;
-                if (mCandidateColors[rowStart][columnEnd] != NULL)
-                    isColumnEnd = true;
-                if (isColumnEnd) {
-                    ++columnEnd;
-                }
-            }
-
-            if ((!isColumnEnd) && isColumnStart) {
-                columnEnd--;
-            }
-            if ((isColumnEnd) && (columnEnd == numVerticalLines)) {
-                columnEnd--;
-                isColumnEnd = false;
-            }
-
-            // Finds the best match on the MacBeth reference color checker for
-            // the continuous block of detected color checker
-            if (isRowStart && (!isRowEnd) &&
-                isColumnStart && (!isColumnEnd)) {
-                findBestMatch(rowStart, rowEnd, columnStart, columnEnd);
-            }
-            ALOGV("FindBestMatch for %d, %d, %d, %d", rowStart,
-                 rowEnd, columnStart, columnEnd);
-
-            // If the column search finishes, go out of the loop
-            if (columnEnd >= numVerticalLines - 1) {
-                successVertical = true;
-            } else {
-                columnStart = columnEnd + 1;
-            }
-        }
-        ALOGV("Continuing to search for direction 1");
-
-        // If the row search finishes, go out of the loop
-        if (rowEnd >= numHorizontalLines - 1) {
-            success = true;
-        } else {
-            rowStart = rowEnd + 1;
-        }
-    }
-
-    for (int i = 0; i < 4; ++i) {
-        for (int j = 0; j < 6; ++j) {
-            if (mMatchPositions[i][j] != NULL) {
-                ALOGV("Reference Match position for (%d, %d) is (%f, %f)", i, j,
-                     mMatchPositions[i][j]->x(), mMatchPositions[i][j]->y());
-            }
-        }
-    }
-
-    fillRefColorGrid();
-}
-
-// Finds the best match on the MacBeth color checker for the continuous block of
-// detected color checkers bounded by row i1, row i2 and column j1 and column j2
-// Assumes that the subsample is less than 4*6.
-void ColorCheckerTest::findBestMatch(int i1, int i2, int j1, int j2) {
-    int numHorizontalGrid = i2 - i1 + 1;
-    int numVerticalGrid = j2 - j1 + 1;
-
-    if (((numHorizontalGrid > 1) || (numVerticalGrid > 1)) &&
-        (numHorizontalGrid <= 4) && (numVerticalGrid <= 6)) {
-        ALOGV("i1, j2, j1, j2 is %d, %d, %d, %d", i1, i2, j1, j2);
-        float minError;
-        float error = 0.f;
-        int horizontalMatch, verticalMatch;
-
-        // Finds the match start point where the error is minimized.
-        for (int i = 0; i < numHorizontalGrid; ++i) {
-            for (int j = 0; j < numVerticalGrid; ++j) {
-                if (mCandidateColors[i1 + i][j1 + j] != NULL) {
-                    error += mCandidateColors[i1 + i][j1 + j]->squareDistance<int>(
-                            *mReferenceColors[i][j]);
-                }
-            }
-        }
-        ALOGV("Error is %f", error);
-        minError = error;
-        horizontalMatch = 0;
-        verticalMatch = 0;
-
-        for (int i = 0; i <= 4 - numHorizontalGrid; ++i) {
-            for (int j = 0; j <= 6 - numVerticalGrid; ++j) {
-                error = 0.f;
-
-                for (int id = 0; id < numHorizontalGrid; ++id) {
-                    for (int jd = 0; jd < numVerticalGrid; ++jd) {
-                        if (mCandidateColors[i1 + id][j1 + jd] != NULL) {
-                            error += mCandidateColors[i1 + id][j1 + jd]->
-                                    squareDistance<int>(
-                                            *mReferenceColors[i + id][j + jd]);
-                        }
-                    }
-                }
-
-                if (error < minError) {
-                    minError = error;
-                    horizontalMatch = i;
-                    verticalMatch = j;
-                }
-                ALOGV("Processed %d, %d and error is %f", i, j, error );
-            }
-        }
-
-        for (int id = 0; id < numHorizontalGrid; ++id) {
-            for (int jd = 0; jd < numVerticalGrid; ++jd) {
-                if (mCandidatePositions[i1 + id][j1 + jd] != NULL) {
-                    mMatchPositions[horizontalMatch + id][verticalMatch + jd] =
-                            new Vec2f(mCandidatePositions[i1 + id][j1 + jd]->x(),
-                                      mCandidatePositions[i1 + id][j1 + jd]->y());
-                }
-            }
-        }
-        ALOGV("Grid match starts at %d, %d", horizontalMatch, verticalMatch);
-    }
-}
-
-// Finds the boundary of a color checker by its color similarity to the center.
-// Also predicts the location of unmatched checkers.
-void ColorCheckerTest::fillRefColorGrid() {
-    int rowStart = 0;
-    int columnStart = 0;
-    bool foundStart = true;
-
-    for (int i = 0; (i < 4) && foundStart; ++i) {
-        for (int j = 0; (j < 6) && foundStart; ++j) {
-            if (mMatchPositions[i][j] != NULL) {
-                rowStart = i;
-                columnStart = j;
-                foundStart = false;
-            }
-        }
-    }
-    ALOGV("First match found at (%d, %d)", rowStart, columnStart);
-
-    float rowDistance, columnDistance;
-    rowDistance = 0;
-    columnDistance = 0;
-    int numRowGrids = 0;
-    int numColumnGrids = 0;
-
-    for (int i = rowStart; i < 4; ++i) {
-        for (int j = columnStart; j < 6; ++j) {
-            if (mMatchPositions[i][j] != NULL) {
-                if (i > rowStart) {
-                    ++numRowGrids;
-                    rowDistance += (mMatchPositions[i][j]->x() -
-                                mMatchPositions[rowStart][columnStart]->x()) /
-                                static_cast<float>(i - rowStart);
-                }
-                if (j > columnStart) {
-                    ++numColumnGrids;
-                    columnDistance += (mMatchPositions[i][j]->y() -
-                                mMatchPositions[rowStart][columnStart]->y()) /
-                                static_cast<float>(j - columnStart);
-                }
-            }
-        }
-    }
-
-    if ((numRowGrids > 0) && (numColumnGrids > 0)) {
-        rowDistance = rowDistance / numRowGrids;
-        columnDistance = columnDistance / numColumnGrids;
-        ALOGV("delta is %f, %f", rowDistance, columnDistance);
-
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0 ; j < 6; ++j) {
-                if (mMatchPositions[i][j] == NULL) {
-                    mMatchPositions[i][j] = new Vec2f(
-                            mMatchPositions[rowStart][columnStart]->x() +
-                                    (i - rowStart) * rowDistance,
-                            mMatchPositions[rowStart][columnStart]->y() +
-                                    (j - columnStart) * columnDistance);
-                }
-            }
-        }
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0; j < 6; ++j) {
-                float radius = 0;
-                Vec3i color = mImage->getPixelValue(*mMatchPositions[i][j]);
-                Vec3f meanColor(0.f , 0.f, 0.f);
-
-                int numPixels = 0;
-                for (int ii  = static_cast<int>(mMatchPositions[i][j]->x() -
-                                                rowDistance/2);
-                     ii <= static_cast<int>(mMatchPositions[i][j]->x() +
-                                            rowDistance/2);
-                     ++ii) {
-                    for (int jj = static_cast<int>(mMatchPositions[i][j]->y() -
-                                                   columnDistance/2);
-                         jj <= static_cast<int>(mMatchPositions[i][j]->y() +
-                                                columnDistance/2);
-                         ++jj) {
-                        if ((ii >= 0) && (ii < mImage->getHeight()) &&
-                            (jj >= 0) && (jj < mImage->getWidth())) {
-                            Vec3i pixelColor = mImage->getPixelValue(ii,jj);
-                            float error = color.squareDistance<int>(pixelColor);
-
-                            if (error < COLOR_ERROR_THRESHOLD) {
-                                drawPoint(ii, jj, *mReferenceColors[i][j]);
-                                meanColor = meanColor + pixelColor;
-                                numPixels++;
-                                Vec2i pixelPosition(ii, jj);
-
-                                if (pixelPosition.squareDistance<float>(
-                                        *mMatchPositions[i][j]) > radius) {
-                                    radius = pixelPosition.squareDistance<float>(
-                                            *mMatchPositions[i][j]);
-                                }
-                            }
-                        }
-                    }
-                }
-
-                /** Computes the radius of the checker.
-                 * The above computed radius is the squared distance to the
-                 * furthest point with a matching color. To be conservative, we
-                 * only consider an area with radius half of the above computed
-                 * value. Since radius is computed as a squared root, the one
-                 * that will be recorded is 1/4 of the above computed value.
-                 */
-                mMatchRadius[i][j] = radius / 4.f;
-                mMatchColors[i][j] = new Vec3f(meanColor / numPixels);
-
-                ALOGV("Reference color at (%d, %d) is (%d, %d, %d)", i, j,
-                     mReferenceColors[i][j]->r(),
-                     mReferenceColors[i][j]->g(),
-                     mReferenceColors[i][j]->b());
-                ALOGV("Average color at (%d, %d) is (%f, %f, %f)", i, j,
-                     mMatchColors[i][j]->r(),
-                     mMatchColors[i][j]->g(),
-                     mMatchColors[i][j]->b());
-                ALOGV("Radius is %f", mMatchRadius[i][j]);
-            }
-        }
-
-        mSuccess = true;
-    }
-}
diff --git a/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp b/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp
deleted file mode 100644
index da9fc40..0000000
--- a/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "ExposureCompensationTest"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <cmath>
-#include <string>
-#include <stdio.h>
-
-#include "vec2.h"
-#include "vec3.h"
-#include "exposurecompensationtest.h"
-
-const float GAMMA_CORRECTION = 2.2f;
-void ExposureCompensationTest::processData() {
-    ALOGV("Start Processing Exposure Compensation Test Data!");
-    clearDebugImage();
-
-    if (mDebugText != NULL) {
-        delete mDebugText;
-        mDebugText = NULL;
-    }
-
-    int numTests = mExposureValues.size();
-    int numPatches = mCheckerColors[0].size();
-    ALOGV("Processing %d tests with %d patches", numTests, numPatches);
-
-    mDebugText = new char[320 * numTests];
-    mDebugText[0] = 0;
-    char* debugText = new char[50];
-
-    Vec3i red(255, 0, 0);
-    Vec3i green(0, 255, 0);
-    Vec3i blue(0, 0, 255);
-
-    float minExposure = -3.0f;
-    float scale = 9.0f;
-    for (int i = 0; i < numTests; ++i) {
-        snprintf(debugText, 50, "Exposure is %f \n", mExposureValues[i]);
-        strcat(mDebugText, debugText);
-        for (int j = 0; j < numPatches; ++j) {
-            int exposureRed = static_cast<int>((
-                log(static_cast<float>(mReferenceColors[j].r()))
-                / log(2.0f) * GAMMA_CORRECTION +
-                mExposureValues[i] - minExposure) * scale);
-            int exposureGreen = static_cast<int>((
-                log(static_cast<float>(mReferenceColors[j].g()))
-                / log(2.0f) * GAMMA_CORRECTION +
-                mExposureValues[i] - minExposure) * scale);
-            int exposureBlue = static_cast<int>((
-                log(static_cast<float>(mReferenceColors[j].b()))
-                / log(2.0f) * GAMMA_CORRECTION +
-                mExposureValues[i] - minExposure) * scale);
-
-            snprintf(debugText, 50, "%d %f %d %f %d %f \n",
-                    exposureRed, mCheckerColors[i][j].r(),
-                    exposureGreen, mCheckerColors[i][j].g(),
-                    exposureBlue, mCheckerColors[i][j].b());
-
-            ALOGV("%s", debugText);
-            strcat(mDebugText, debugText);
-
-            drawPoint(200 - exposureRed, mCheckerColors[i][j].r(), red);
-            drawPoint(200 - exposureGreen, mCheckerColors[i][j].g(), green);
-            drawPoint(200 - exposureBlue, mCheckerColors[i][j].b(), blue);
-        }
-    }
-    mExposureValues.clear();
-    mCheckerColors.clear();
-}
-
-void ExposureCompensationTest::initializeReferenceColors() {
-    mReferenceColors.resize(6);
-
-    mReferenceColors[0].set(243, 243, 242);
-    mReferenceColors[1].set(200, 200, 200);
-    mReferenceColors[2].set(160, 160, 160);
-    mReferenceColors[3].set(122, 122, 121);
-    mReferenceColors[4].set(85, 85, 85);
-    mReferenceColors[5].set(52, 52, 52);
-}
diff --git a/apps/CtsVerifier/lib/colorchecker/imagetesthandler.cpp b/apps/CtsVerifier/lib/colorchecker/imagetesthandler.cpp
deleted file mode 100644
index cc3bca9..0000000
--- a/apps/CtsVerifier/lib/colorchecker/imagetesthandler.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "ImageTestHandler"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <cmath>
-#include <cstring>
-
-#include "vec2.h"
-#include "vec3.h"
-#include "imagetesthandler.h"
-
-void ImageTestHandler::initDebugImage() {
-    mDebugOutput = NULL;
-}
-
-// Initializes the  debug image with a given height and width.
-void ImageTestHandler::initDebugImage(int debugHeight,
-                                      int debugWidth) {
-    mDebugOutput = NULL;
-    mDebugOutput = new unsigned char[debugHeight * debugWidth * 4];
-    memset(mDebugOutput, 0, debugHeight * debugWidth * 4);
-
-    mDebugHeight = debugHeight;
-    mDebugWidth = debugWidth;
-}
-
-// Copies an existing image to the debug image.
-void ImageTestHandler::copyDebugImage(int inputHeight, int inputWidth,
-                                      const unsigned char* inputImage) {
-    if ((inputHeight == mDebugHeight) && (inputWidth == mDebugWidth)) {
-        ALOGV("Copying debug images");
-        memcpy(mDebugOutput, inputImage, mDebugHeight * mDebugWidth * 4);
-    }
-}
-
-void ImageTestHandler::clearDebugImage() {
-    if (mDebugOutput != NULL) {
-        delete[] mDebugOutput;
-        mDebugOutput = new unsigned char[mDebugHeight * mDebugWidth * 4];
-        memset(mDebugOutput, 0, mDebugHeight * mDebugWidth * 4);
-    }
-}
-
-
-// Draws a point of a given color.
-void ImageTestHandler::drawPoint(int row, int column, const Vec3i &color) {
-    if ((row >= 0) && (column >= 0) &&
-        (column < mDebugWidth) && (row < mDebugHeight)) {
-        mDebugOutput[(row*mDebugWidth + column) * 4] = color.r();
-        mDebugOutput[(row*mDebugWidth + column) * 4+1] = color.g();
-        mDebugOutput[(row*mDebugWidth + column) * 4+2] = color.b();
-        mDebugOutput[(row*mDebugWidth + column) * 4+3] = 255;
-    }
-}
-
-// Draws a point in Vec2 format of a given color.
-void ImageTestHandler::drawPoint(const Vec2i &point, const Vec3i &color) {
-    drawPoint((int) point.y(), (int) point.x(), color);
-}
-
-// Draws a line of a given color.
-void ImageTestHandler::drawLine(int angle, int radius, const Vec3i &color) {
-    const int r = color.r();
-    const int g = color.g();
-    const int b = color.b();
-    const int a = 255;
-
-    int shiftedMin = -113;
-    int shiftedMax = 83;
-
-    float radiusDouble = static_cast<float>(radius);
-
-    float angleRad = static_cast<float>(angle) * M_PI / 180.0;
-
-    //ALOGV("draw line for (%d, %d)", angle, radius);
-    for (int i = shiftedMin; i <= shiftedMax; ++i) {
-        float j;
-
-        assert(angle != 0);
-        j = (i - radiusDouble / sin(angleRad)) * tan(angleRad);
-        float x = (static_cast<float>(i) + j) / sqrt(2.0);
-        float y = (j - static_cast<float>(i)) / sqrt(2.0);
-
-        drawPoint(x, y, color);
-    }
-}
diff --git a/apps/CtsVerifier/lib/colorchecker/meteringtest.cpp b/apps/CtsVerifier/lib/colorchecker/meteringtest.cpp
deleted file mode 100644
index 47de5d8..0000000
--- a/apps/CtsVerifier/lib/colorchecker/meteringtest.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "MeteringTest"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <cmath>
-#include <string>
-
-#include "vec2.h"
-#include "vec3.h"
-#include "meteringtest.h"
-
-const float kOverExposure = 230.f;
-const float kEqThreshold = 0.05f;
-// Processes the checker colors stored by comparing the pixel values from the
-// two scenarios in a test.
-void MeteringTest::processData() {
-    ALOGV("Start Processing Metering Test Data!");
-
-    int numTests = mCheckerColors.size() / 2;
-    mNumPatches = 0;
-
-    if (numTests > 0) {
-        mNumPatches = mCheckerColors[0].size();
-    }
-
-    for (int i = 0; i < numTests; ++i) {
-        mComparisonResults.push_back(
-                isEquivalentTo((&mCheckerColors[i * 2]),
-                               (&mCheckerColors[i * 2 + 1])));
-        mComparisonResults.push_back(
-                isDarkerThan((&mCheckerColors[i * 2]),
-                             (&mCheckerColors[i * 2 + 1])));
-    }
-}
-
-void MeteringTest::clearData() {
-    mComparisonResults.clear();
-    mCheckerColors.clear();
-}
-
-// Compares two given arrays of pixel values and decide whether the first one is
-// significantly darker than the second one.
-bool MeteringTest::isDarkerThan(
-        const std::vector<Vec3f>* checkerColors1,
-        const std::vector<Vec3f>* checkerColors2) const {
-    float meanRatio = 0.f;
-    int meanNumCount = 0;
-
-    for (int i = 0; i < mNumPatches; ++i) {
-        float luminance1 = (*checkerColors1)[i].convertToLuminance();
-        float luminance2 = (*checkerColors2)[i].convertToLuminance();
-
-        // Out of the saturation rage, define 5% as a margin for being
-        // significantly brighter.
-        if ((luminance2 < kOverExposure) && (luminance1 != 0.f)) {
-            meanRatio += luminance2 / luminance1;
-            ++meanNumCount;
-        }
-    }
-    meanRatio = meanRatio / meanNumCount;
-
-    return (meanRatio > 1 + kEqThreshold);
-}
-
-// Compares the two givn arrays of pixel values and decide whether they are
-// equivalent within an acceptable range.
-bool MeteringTest::isEquivalentTo(
-        const std::vector<Vec3f>* checkerColors1,
-        const std::vector<Vec3f>* checkerColors2) const {
-    float meanRatio = 0.f;
-    int meanNumCount = 0;
-
-    for (int i = 0; i < mNumPatches; ++i) {
-        float luminance1 = (*checkerColors1)[i].convertToLuminance();
-        float luminance2 = (*checkerColors2)[i].convertToLuminance();
-        ALOGV("Luma_1 and Luma_2 is %f, %f", luminance1, luminance2);
-
-        if ((luminance1 < kOverExposure) && (luminance2 < kOverExposure)) {
-              meanRatio += luminance2 / luminance1;
-              ++meanNumCount;
-        }
-    }
-    meanRatio = meanRatio / meanNumCount;
-
-    return ((meanRatio >= 1 - kEqThreshold) && (meanRatio <= 1 + kEqThreshold));
-}
diff --git a/apps/CtsVerifier/lib/colorchecker/testingimage.cpp b/apps/CtsVerifier/lib/colorchecker/testingimage.cpp
deleted file mode 100644
index 28f025f..0000000
--- a/apps/CtsVerifier/lib/colorchecker/testingimage.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "TestingImage"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <string.h>
-#include <cmath>
-#include <vector>
-#include <assert.h>
-#include "vec3.h"
-
-#include "testingimage.h"
-
-const float GAMMA_CORRECTION = 2.2f;
-
-// Constructs an instance with the given image byte array.
-TestingImage::TestingImage(const unsigned char* inputImage,
-                           int inputHeight, int inputWidth,
-                           int inputChannel, int inputRowSpan) {
-    mImage = new unsigned char[inputRowSpan * inputHeight];
-
-    ALOGV("mImage format created! with size as %d, %d, %d",
-         inputRowSpan, inputHeight, inputChannel);
-    mWidth = inputWidth;
-    mHeight = inputHeight;
-    mChannels = inputChannel;
-    mRowSpan = mWidth * mChannels;
-
-    for (int i = 0; i < mHeight; ++i) {
-        for (int j = 0; j < mWidth; ++j) {
-            for (int k = 0; k < mChannels; ++k) {
-                mImage[i * mRowSpan + j* mChannels + k] =
-                        inputImage[i * inputRowSpan + j * inputChannel + k];
-            }
-        }
-    }
-    ALOGV("mImage converted!");
-}
-
-// Constructs an instance with the given image and resize it to a new size.
-TestingImage::TestingImage(const unsigned char* inputImage,
-                           int inputHeight, int inputWidth,
-                           int inputChannel, int inputRowSpan,
-                           int newHeight, int newWidth) {
-    mImage = new unsigned char[newHeight * newWidth * inputChannel];
-
-    ALOGV("mImage format created! with size as %d, %d, %d",
-         newHeight, newWidth, inputChannel);
-    mHeight = newHeight;
-    mWidth = newWidth;
-    mChannels = inputChannel;
-    mRowSpan = mWidth * mChannels;
-
-    // Computes how many pixels in the original image corresponds to one pixel
-    // in the new image.
-    int heightScale = inputHeight / newHeight;
-    int widthScale = inputWidth / newWidth;
-
-    // Average the corresponding pixels in the original image to compute the
-    // pixel value of the new image.
-    for (int i = 0; i < mHeight; ++i) {
-        for (int j = 0; j < mWidth; ++j) {
-            for (int k = 0; k < mChannels; ++k) {
-                int pixelValue = 0;
-
-                for (int l = 0; l < heightScale; ++l) {
-                    for (int m = 0; m < widthScale; ++m) {
-                        pixelValue += inputImage[
-                                (i * heightScale + l) * inputRowSpan
-                                + (j * widthScale + m) * inputChannel + k];
-                    }
-                }
-                pixelValue = pixelValue / (heightScale * widthScale);
-                mImage[i * mRowSpan + j * mChannels + k] =
-                        (unsigned char) pixelValue;
-            }
-        }
-    }
-}
-
-TestingImage::~TestingImage() {
-    if (mImage!=NULL) {
-        delete[] mImage;
-    }
-}
-
-int TestingImage::getPixelValue(int row, int column, int channel) const {
-    assert ((row >= 0) && (row < mHeight));
-    assert ((column >= 0) && (column < mWidth));
-    assert ((channel >= 0) && (channel < mChannels));
-    return (int)mImage[row * mRowSpan + column * mChannels + channel];
-}
-
-Vec3i TestingImage::getPixelValue(int row, int column) const {
-    Vec3i current_color(getPixelValue(row, column, 0),
-                        getPixelValue(row, column, 1),
-                        getPixelValue(row, column, 2));
-    return current_color;
-}
-
-Vec3i TestingImage::getPixelValue(const Vec2i &pixelPosition) const {
-    return getPixelValue(pixelPosition.x(), pixelPosition.y());
-}
-
-Vec3i TestingImage::getPixelValue(const Vec2f &pixelPosition) const {
-    return getPixelValue(static_cast<int>(pixelPosition.x()),
-                         static_cast<int>(pixelPosition.y()));
-}
-
-// Returns a vector of the colors in the requested block of color checkers.
-// The vector is formatted by going through the block from left to right and
-// from top to bottom.
-const std::vector<Vec3f>* TestingImage::getColorChecker(
-      int rowStart, int rowEnd, int columnStart, int columnEnd,
-      const std::vector<std::vector< Vec2f > >* centerAddress,
-      const std::vector<std::vector< float > >* radiusAddress) const {
-    std::vector<Vec3f>* checkerColors = new std::vector<Vec3f>;
-
-    // Average the pixel values of the pixels within the given radius to the
-    // given center position.
-    for (int i = rowStart; i < rowEnd; ++i) {
-        for (int j = columnStart; j < columnEnd; ++j) {
-            float radius = sqrt((*radiusAddress)[i][j]);
-            Vec2f center((*centerAddress)[i][j].x(),
-                               (*centerAddress)[i][j].y());
-            Vec3f meanColor(0.f, 0.f, 0.f);
-            int numPixels = 0;
-
-            for (int ii = static_cast<int>(center.x() - radius);
-                 ii < static_cast<int>(center.x() + radius); ++ii) {
-                for (int jj = static_cast<int>(center.y() - radius);
-                     jj < static_cast<int>(center.y() + radius); ++jj) {
-
-                    Vec2i pixelPosition(ii,jj);
-                    if (pixelPosition.squareDistance<float>(center) <
-                        (*radiusAddress)[i][j]) {
-                        meanColor = meanColor + getPixelValue(pixelPosition);
-                        ++numPixels;
-                    }
-                }
-            }
-            meanColor = meanColor / numPixels;
-            checkerColors->push_back(meanColor);
-        }
-    }
-
-    return checkerColors;
-}
-
-bool TestingImage::rgbToGrayScale(unsigned char* grayLayer) const {
-    if (mChannels == 4) {
-        for (int i = 0; i < mWidth; i++) {
-            for (int j = 0; j < mHeight; j++) {
-                float redLinear = pow(getPixelValue(j, i, 0),
-                                       GAMMA_CORRECTION);
-                float greenLinear = pow(getPixelValue(j,i,1),
-                                         GAMMA_CORRECTION);
-                float blueLinear = pow(getPixelValue(j,i,2),
-                                        GAMMA_CORRECTION);
-
-                // Computes the luminance value
-                grayLayer[j * mWidth + i] =
-                        (unsigned char)((int)pow((0.299f * redLinear
-                                                  + 0.587f * greenLinear
-                                                  + 0.114f * blueLinear),
-                                                  1/GAMMA_CORRECTION));
-            }
-        }
-
-        return true;
-    } else {
-
-        return false;
-    }
-}
diff --git a/apps/CtsVerifier/lib/colorchecker/vec2.cpp b/apps/CtsVerifier/lib/colorchecker/vec2.cpp
deleted file mode 100644
index 29736bb..0000000
--- a/apps/CtsVerifier/lib/colorchecker/vec2.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "Vec2"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#include "vec2.h"
diff --git a/apps/CtsVerifier/lib/colorchecker/whitebalancetest.cpp b/apps/CtsVerifier/lib/colorchecker/whitebalancetest.cpp
deleted file mode 100644
index 6413a2b..0000000
--- a/apps/CtsVerifier/lib/colorchecker/whitebalancetest.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-#define LOG_NDEBUG 0
-
-#define LOG_TAG "WhiteBalanceTest"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-#include <cmath>
-#include <string>
-
-#include "vec2.h"
-#include "vec3.h"
-#include "whitebalancetest.h"
-
-// White point in XYZ color space under 5200k illumination.
-const Vec3f kDaylightWhitePoint(0.9781f, 1.f, 0.9021f);
-
-// Process the data of checker colors collected under different white balance.
-// Assuming the Daylight CCT is set to 5200k, compute the CCT of other white
-// balance modes.
-void WhiteBalanceTest::processData() {
-    ALOGV("Start Processing White Balance Test Data!");
-
-    int numPatches = mCheckerColors.size();
-    ALOGV("Processing %d tests with %d patches", 2, numPatches);
-
-    std::vector<Vec3f> xyzColors(numPatches);
-    for (int j = 0; j < numPatches; ++j) {
-        Vec3f xyzCheckerColor = initializeFromRGB(mCheckerColors[j]);
-        xyzColors[j] = xyzCheckerColor;
-        ALOGV("XYZ coordinate is %f, %f, %f", xyzCheckerColor.r(),
-              xyzCheckerColor.g(), xyzCheckerColor.b());
-    }
-
-    Vec3f meanScale(0.f, 0.f, 0.f);
-
-    if (mMode == "daylight") {
-        mXyzColorsDaylight = xyzColors;
-        // For testing the auto white balance mode. Compute a CCT that would
-        // map the gray checkers to a white point.
-        for (int j = 1; j < numPatches; ++j) {
-            meanScale = meanScale +
-                    (mXyzColorsDaylight[j] / kDaylightWhitePoint);
-        }
-    } else {
-        for (int j = 1; j < numPatches; ++j) {
-            meanScale = meanScale + (mXyzColorsDaylight[j] / xyzColors[j]);
-        }
-    }
-
-    meanScale = meanScale / (numPatches - 1);
-    ALOGV("Scale: %f, %f, %f", meanScale.r(), meanScale.g(), meanScale.b());
-
-    Vec3f whitePoint;
-    whitePoint = meanScale * kDaylightWhitePoint;
-
-    ALOGV("White point is %f, %f, %f", whitePoint.r(),
-         whitePoint.g(), whitePoint.b());
-
-    mCorrelatedColorTemp = findCorrelatedColorTemp(whitePoint);
-    ALOGV("CCT is %d", mCorrelatedColorTemp);
-}
-
-// Given a white point, find the correlated color temperature.
-// Formula taken from the paper "Calculating Correlated Color Temperatures
-// Across the Entire Gamut of Daylight and Skylight Chromaticities" by Hernandez
-// Andres et al. in 1999. The numbers are fitting parameters.
-int WhiteBalanceTest::findCorrelatedColorTemp(const Vec3f &whitePoint) {
-    Vec2f chromaOfWhitePoint(
-        whitePoint.r() / (whitePoint.r() + whitePoint.g() + whitePoint.b()),
-        whitePoint.g() / (whitePoint.r() + whitePoint.g() + whitePoint.b()));
-
-    float n = (chromaOfWhitePoint.x() - 0.3366f)
-                / (chromaOfWhitePoint.y() - 0.1735f);
-    float y = -949.86315f + 6253.80338f * exp(-n / 0.92159f)
-               + 28.70599f * exp(-n / 0.20039f) + 0.00004f * exp(-n / 0.07125f);
-
-    return static_cast<int>(y);
-}
-
-// Converts a RGB pixel value to XYZ color space.
-Vec3f WhiteBalanceTest::initializeFromRGB(const Vec3f &rgb) {
-    float linearRed = convertToLinear(rgb.r());
-    float linearGreen = convertToLinear(rgb.g());
-    float linearBlue = convertToLinear(rgb.b());
-
-    float x = 0.4124f * linearRed + 0.3576f * linearGreen +
-            0.1805f * linearBlue;
-    float y = 0.2126f * linearRed + 0.7152f * linearGreen +
-            0.0722f * linearBlue;
-    float z = 0.0193f * linearRed + 0.1192f * linearGreen +
-            0.9505f * linearBlue;
-
-    return Vec3f(x, y, z);
-}
-
-float WhiteBalanceTest::convertToLinear(float color) {
-    float norm = color/ 255.0f;
-    float linearColor;
-
-    // Convert from sRGB space to linear RGB value
-    if (norm > 0.04045f) {
-        linearColor = pow(((norm + 0.055f) / 1.055f), 2.4f);
-    } else {
-        linearColor = norm / 12.92f;
-    }
-
-    return linearColor;
-}
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index ca4680f..fe7eed8 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -19,3 +19,5 @@
 -dontwarn android.hardware.Sensor
 -dontwarn android.test.AndroidTestRunner
 -dontwarn java.util.concurrent.ConcurrentLinkedDeque
+-dontwarn android.cts.util.**
+-dontwarn junit.**
diff --git a/apps/CtsVerifier/res/layout/ca_main.xml b/apps/CtsVerifier/res/layout/ca_main.xml
deleted file mode 100644
index 274430d..0000000
--- a/apps/CtsVerifier/res/layout/ca_main.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- Copyright (C) 2011 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.
--->
-<android.support.wearable.view.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <LinearLayout app:layout_box="all"
-      android:orientation="vertical" android:layout_width="fill_parent"
-      android:layout_height="fill_parent">
-
-
-      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="horizontal" android:layout_width="fill_parent"
-        android:layout_height="wrap_content">
-        <!--Button android:id="@+id/focusmodesbutton" android:layout_width="0px"
-          android:layout_height="wrap_content" android:text="@string/ca_focus_modes_label"
-          android:layout_weight="1" /-->
-        <Button android:id="@+id/findcheckerboardbutton" android:layout_width="0px"
-          android:layout_height="wrap_content" android:text="@string/ca_find_checkerboard_label"
-          android:layout_weight="1" />
-
-        <Button android:id="@+id/meteringbutton" android:layout_width="0px"
-          android:layout_height="wrap_content" android:text="@string/ca_metering_label"
-          android:layout_weight="1" />
-
-        <Button android:id="@+id/exposurecompensationbutton" android:layout_width="0px"
-          android:layout_height="wrap_content" android:text="@string/ca_exposure_test_label"
-          android:layout_weight="1"/>
-
-        <Button android:id="@+id/whitebalancebutton" android:layout_width="0px"
-          android:layout_height="wrap_content" android:text="@string/ca_wb_test_label"
-          android:layout_weight="1" />
-
-        <Button android:id="@+id/lockbutton" android:layout_width="0px"
-          android:layout_height="wrap_content" android:text="@string/ca_lock_test_label"
-          android:layout_weight="1" />
-      </LinearLayout>
-
-      <LinearLayout android:orientation="horizontal"
-        android:layout_width="fill_parent" android:layout_height="0px"
-        android:layout_weight="1">
-
-        <SurfaceView android:id="@+id/cameraview" android:layout_height="fill_parent"
-          android:layout_width="wrap_content"
-          android:layout_weight="0" />
-
-        <LinearLayout android:orientation="vertical"
-          android:layout_width="fill_parent" android:layout_height="match_parent"
-          android:layout_weight="1">
-
-           <ListView android:id="@+id/ca_tests"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_marginLeft="10px"/>
-
-          <ImageView android:id="@+id/resultview" android:layout_height="wrap_content"
-            android:layout_width="fill_parent"
-            android:layout_weight="1" />
-        </LinearLayout>
-
-      </LinearLayout>
-
-      <include layout="@layout/pass_fail_buttons" />
-
-    </LinearLayout>
-</android.support.wearable.view.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/layout/hifi_ultrasound.xml b/apps/CtsVerifier/res/layout/hifi_ultrasound.xml
new file mode 100644
index 0000000..7d2de5a
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/hifi_ultrasound.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+  <TextView
+      android:layout_width="match_parent"
+      android:layout_height="0dp"
+      android:layout_weight="7"
+      android:scrollbars="vertical"
+      android:gravity="bottom"
+      android:id="@+id/info_text"/>
+
+  <LinearLayout
+      android:layout_width="match_parent"
+      android:layout_height="0dp"
+      android:layout_weight="3"
+      android:orientation="horizontal">
+    <Button
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="5"
+        android:text="@string/hifi_ultrasound_test_record"
+        android:id="@+id/recorder_button"/>
+    <Button
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="5"
+        android:text="@string/hifi_ultrasound_test_play"
+        android:id="@+id/player_button"/>
+  </LinearLayout>
+
+  <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/hifi_ultrasound_popup.xml b/apps/CtsVerifier/res/layout/hifi_ultrasound_popup.xml
new file mode 100644
index 0000000..afff2c9
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/hifi_ultrasound_popup.xml
@@ -0,0 +1,33 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:background="@android:color/white"
+              android:gravity="center"
+              android:orientation="vertical" >
+
+    <com.androidplot.xy.XYPlot
+        android:id="@+id/responseChart"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="9"
+        androidPlot.domainLabel="kHz"
+        androidPlot.rangeLabel="dB"
+        androidPlot.domainLabelWidget.labelPaint.textSize="16dp"
+        androidPlot.rangeLabelWidget.labelPaint.textSize="16dp"
+        androidPlot.graphWidget.rangeLabelPaint.textSize="16dp"
+        androidPlot.graphWidget.rangeOriginLabelPaint.textSize="16dp"
+        androidPlot.graphWidget.domainLabelPaint.textSize="16dp"
+        androidPlot.graphWidget.domainOriginLabelPaint.textSize="16dp"
+        androidPlot.legendWidget.textPaint.textSize="16dp"
+        androidPlot.legendWidget.iconSizeMetrics.heightMetric.value="16dp"
+        androidPlot.legendWidget.iconSizeMetrics.widthMetric.value="16dp"
+        androidPlot.legendWidget.heightMetric.value="16dp"
+        androidPlot.graphWidget.gridLinePaint.color="#000000" />
+
+    <Button
+        android:id="@+id/dismiss"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:text="@string/hifi_ultrasound_test_dismiss" />
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index de39275..7420363 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -286,6 +286,22 @@
 
     <string name="empty"></string>
 
+    <!-- Strings for HifiUltrasoundTestActivity -->
+    <string name="hifi_ultrasound_test">Hifi Ultrasound Test</string>
+    <string name="hifi_ultrasound_test_info">This is a test for near-ultrasound response.\n
+        This test requires two devices, one as recording device, one as playback device.\n</string>
+    <string name="hifi_ultrasound_test_play">GENERATE</string>
+    <string name="hifi_ultrasound_test_record">RECORD</string>
+    <string name="hifi_ultrasound_test_playback">PLAY</string>
+    <string name="hifi_ultrasound_test_plot">PLOT</string>
+    <string name="hifi_ultrasound_test_dismiss">DISMISS</string>
+    <string name="hifi_ultrasound_test_instruction1">
+        Set the volume of the playback device at 70% and hold it with one hand.\n
+        Hold the recording device with the other hand\n
+        Press the RECORD button on the recording device, the GENERATE button on the playback device simultaneously.\n</string>
+    <string name="hifi_ultrasound_test_pass">PASS</string>
+    <string name="hifi_ultrasound_test_fail">FAIL</string>
+
     <!-- Strings for Location tests -->
     <string name="location_gps_test">GPS Test</string>
     <string name="location_gps_test_info">This test verifies basic GPS behavior
@@ -624,18 +640,6 @@
     <string name="congratulations">Congratulations!</string>
     <string name="no_suid_files">No unauthorized suid files detected!</string>
 
-    <!-- Strings for Camera Analyzer -->
-    <string name="camera_analyzer">Camera Analyzer</string>
-    <string name="ca_find_checkerboard_label">Find target</string>
-    <string name="ca_check_formats_label">Output formats</string>
-    <string name="ca_exposure_test_label">Exposure Comp.</string>
-    <string name="ca_result_label">Results will be here</string>
-    <string name="ca_wb_test_label">White Balance</string>
-    <string name="ca_lock_test_label">AE Lock</string>
-    <string name="ca_metering_label">Metering Area</string>
-    <string name="ca_focus_modes_label">Focus Modes</string>
-    <string name="ca_info">This test checks the image quality of the camera of this device. It requires a MacBeth 4x6 color checker. With an ADK board and a lamp connected to it on the Relay 1 port, all tests can be run automatically. Without the ADK board, all the tests except the Auto Exposure Lock Test can be run automatically and the Auto Exposure Lock Test will require users to turn on/off a lamp according to the instruction given. </string>
-
     <!-- Strings for Camera Orientation -->
     <string name="camera_orientation">Camera Orientation</string>
     <string name="co_info">This test verifies the orientation capabilities of
@@ -1362,6 +1366,7 @@
         Then use the Back button to return to this test and mark accordingly.
     </string>
 
+    <string name="provisioning_byod_cross_profile_intent_filters">Cross profile intent filters are set</string>
     <string name="provisioning_byod_no_activity">Cannot communicate with activity in the work profile.</string>
     <string name="provisioning_byod_delete_profile">Initiate deletion of work profile.</string>
     <string name="provisioning_byod_profile_deleted">Work profile deleted.</string>
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml
new file mode 100644
index 0000000..9c6de77
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config
+        linePaint.strokeWidth="3dp"
+        linePaint.color="#AA0000"
+        vertexPaint.color="#770000"
+        fillPaint.color="#00000000" />
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml
new file mode 100644
index 0000000..8fb236e
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config
+        linePaint.strokeWidth="2dp"
+        linePaint.color="#777777"
+        vertexPaint.color="777777"
+        fillPaint.color="#00000000" />
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml
new file mode 100644
index 0000000..9a6c29a
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config
+        linePaint.strokeWidth="2dp"
+        linePaint.color="#007700"
+        vertexPaint.color="#007700"
+        fillPaint.color="#00000000" />
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml
new file mode 100644
index 0000000..3f9ffc2
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config
+        linePaint.strokeWidth="1dp"
+        linePaint.color="#AAAAAA"
+        vertexPaint.color="#777777"
+        fillPaint.color="#00000000" />
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRecordHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRecordHelper.java
new file mode 100644
index 0000000..dafa117
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRecordHelper.java
@@ -0,0 +1,164 @@
+package com.android.cts.verifier.audio;
+
+import android.media.AudioFormat;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * A wrapper on AudioRecord class.
+ */
+public class AudioRecordHelper {
+
+  // order of preference
+  // MIC 48000Hz
+  // MIC 44100Hz
+  // VOICE_RECOGNITION 48000Hz
+  // VOICE_RECOGNITION 44100Hz
+  // if all these 4 settings failed, it logs an error
+  private static final int[] SOURCE = {
+      MediaRecorder.AudioSource.MIC, MediaRecorder.AudioSource.VOICE_RECOGNITION};
+  private static final int[] SAMPLE_RATES_HZ = {48000, 44100};
+
+  private static final int CHANNEL = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+  private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
+  private static final String TAG = "AudioRecordHelper";
+  private static AudioRecordHelper instance;
+  private final int bufferSize;
+  private final int sampleRate;
+  private final int source;
+  private ByteArrayOutputStream os;
+  private AudioRecord audioRecord;
+  private volatile boolean isRecording = false;
+
+  private AudioRecordHelper() {
+    int tmpBufferSize = 0;
+    int tmpSampleRate = 0;
+    int tmpSource = 0;
+    initialization:
+    for (int source : SOURCE) {
+      for (int rate : SAMPLE_RATES_HZ) {
+        tmpBufferSize = AudioRecord.getMinBufferSize(rate, CHANNEL, ENCODING);
+        AudioRecord testAudioRecord = new AudioRecord(source, rate, CHANNEL, ENCODING,
+            tmpBufferSize);
+        if (testAudioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
+          testAudioRecord.release();
+          tmpSampleRate = rate;
+          tmpSource = source;
+          break initialization;
+        }
+      }
+    }
+    if (tmpBufferSize == 0 || tmpSampleRate == 0) {
+      Log.e(TAG, "Failed to initialize");
+    }
+    bufferSize = tmpBufferSize;
+    sampleRate = tmpSampleRate;
+    source = tmpSource;
+    Log.d(TAG, "Sample rate = " + sampleRate + "Hz, Source = "
+        + source + " (VOICE_RECOGNITION = 6 , MIC = 1)");
+  }
+
+  public static AudioRecordHelper getInstance() {
+    if (instance == null) {
+      instance = new AudioRecordHelper();
+    }
+    return instance;
+  }
+
+  /**
+   * Start recording.
+   */
+  public void start() {
+    if (!isRecording) {
+      isRecording = true;
+      os = new ByteArrayOutputStream();
+      audioRecord = new AudioRecord(source, sampleRate, CHANNEL, ENCODING, bufferSize);
+      audioRecord.startRecording();
+      startPullingData();
+    }
+  }
+
+  /**
+   * Stop recording
+   */
+  public void stop() {
+    if (isRecording) {
+      isRecording = false;
+      audioRecord.stop();
+      audioRecord.release();
+      audioRecord = null;
+      try {
+        os.close();
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private void startPullingData() {
+    new Thread() {
+      @Override
+      public void run(){
+        byte data[] = new byte[bufferSize];
+        while (isRecording) {
+          int read = audioRecord.read(data, 0, bufferSize);
+          if (read > 0) {
+            os.write(data, 0, read);
+          }
+          if (read < 0) {
+            break;
+          }
+        }
+      }
+    }.start();
+  }
+
+  /**
+   * Returns the sample rate for this recorder.
+   */
+  public int getSampleRate() {
+    return sampleRate;
+  }
+
+  /**
+   * Returns the audio source currently being used.
+   */
+  public int getAudioSource() {
+    return source;
+  }
+
+  /**
+   * Returns true if recorder is recording; False if not.
+   */
+  public boolean isRecording() {
+    return isRecording;
+  }
+
+  /**
+   * Returns the raw data.
+   */
+  public byte[] getByte() {
+    return os.toByteArray();
+  }
+
+  /**
+   * Writes data to file
+   */
+  public void writeToFile() {
+    try {
+      FileOutputStream fos = new FileOutputStream(new File(Common.PCM_FILE));
+      fos.write(os.toByteArray());
+    } catch (FileNotFoundException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java
new file mode 100644
index 0000000..f30b990
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java
@@ -0,0 +1,144 @@
+package com.android.cts.verifier.audio;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * This class stores common constants and methods.
+ */
+public class Common {
+
+  // Default constants.
+  public static final double PIP_DURATION_S = 0.004;
+  public static final double PAUSE_DURATION_S = 0.016;
+  public static final int PREFIX_NUM_CHIPS = 1023;
+  public static final int PREFIX_SAMPLES_PER_CHIP = 4;
+  public static final int PREFIX_LENGTH =
+      PREFIX_NUM_CHIPS * PREFIX_SAMPLES_PER_CHIP;
+  public static final double PAUSE_BEFORE_PREFIX_DURATION_S = 1.0;
+  public static final double PAUSE_AFTER_PREFIX_DURATION_S = 0.5;
+  public static final double MIN_FREQUENCY_HZ = 500;
+  public static final double MAX_FREQUENCY_HZ = 21000;
+  public static final double FREQUENCY_STEP_HZ = 100;
+  public static final int AUDIBLE_SIGNAL_MIN_STRENGTH_DB = 10;
+  public static final int ULTRASOUND_SIGNAL_MIN_STRENGTH_RATIO = 2;
+  // Variables defined for convenience.
+  public static final int REPETITIONS = 5;
+  public static final double[] PREFIX = prefix();
+  public static final double[] FREQUENCIES_ORIGINAL = originalFrequencies();
+  public static final int PIP_NUM = FREQUENCIES_ORIGINAL.length;
+  public static final int[] ORDER = order();
+  public static final double[] FREQUENCIES = frequencies();
+  // A PCM file is just raw monaural sample data. Samples are serialized as little endian signed
+  // 16-bit integers. The sample rate is determined by AudioRecordHelper.getSampleRate().
+  public static final String PCM_FILE = "/sdcard/sound_self_tester.pcm";
+  private static int recordingSampleRateHz = -1;
+  private static double[] window;
+  private static double[] generateWindow;
+
+  public static int getSampleRate() {
+    return recordingSampleRateHz;
+  }
+
+  public static void setSampleRate(int sampleRate) {
+    recordingSampleRateHz = sampleRate;
+    window = hann(Util.toLength(PIP_DURATION_S, recordingSampleRateHz));
+    generateWindow = hann(Util.toLength(PIP_DURATION_S, recordingSampleRateHz));
+  }
+
+  public static double[] window() {
+    return window;
+  }
+
+  public static double[] generateWindow() {
+    return generateWindow;
+  }
+
+  /**
+   * Get a Hann window.
+   */
+  private static double[] hann(int windowWidth) {
+    double[] envelopeArray = new double[windowWidth];
+    for (int i = 0; i < windowWidth; i++) {
+      envelopeArray[i] = 0.5
+          * (1 - Math.cos(2 * Math.PI * i / windowWidth));
+    }
+    return envelopeArray;
+  }
+
+  /**
+   * Get a maximum length sequence, used as prefix to indicate start of signal.
+   */
+  private static double[] prefix() {
+    double[] codeSequence = new double[PREFIX_NUM_CHIPS];
+    for (int i = 0; i < PREFIX_NUM_CHIPS; i++) {
+      if (i < 10) {
+        codeSequence[i] = 1;
+      } else {
+        codeSequence[i] = -codeSequence[i - 6] * codeSequence[i - 7]
+            * codeSequence[i - 9] * codeSequence[i - 10];
+      }
+    }
+    double[] prefixArray = new double[PREFIX_LENGTH];
+    int offset = 0;
+    for (int i = 0; i < PREFIX_NUM_CHIPS; i++) {
+      double value = codeSequence[i];
+      for (int j = 0; j < PREFIX_SAMPLES_PER_CHIP; j++) {
+        prefixArray[offset + j] = value;
+      }
+      offset += PREFIX_SAMPLES_PER_CHIP;
+    }
+    return prefixArray;
+  }
+
+  /**
+   * Returns array consists the frequencies of the test pips in the order that will be used in test.
+   */
+  private static double[] frequencies() {
+    double[] originalFrequencies = originalFrequencies();
+
+    double[] randomFrequencies = new double[Common.REPETITIONS * originalFrequencies.length];
+    for (int i = 0; i < REPETITIONS * originalFrequencies.length; i++) {
+      randomFrequencies[i] = originalFrequencies[ORDER[i] % originalFrequencies.length];
+    }
+
+    return randomFrequencies;
+  }
+
+  /**
+   * Returns array consists the frequencies of the test pips.
+   */
+  private static double[] originalFrequencies() {
+    ArrayList<Double> frequencies = new ArrayList<Double>();
+    double frequency = Common.MIN_FREQUENCY_HZ;
+    while (frequency <= Common.MAX_FREQUENCY_HZ) {
+      frequencies.add(new Double(frequency));
+      if ((frequency >= 18500) && (frequency < 20000)) {
+        frequency += Common.FREQUENCY_STEP_HZ;
+      } else {
+        frequency += Common.FREQUENCY_STEP_HZ * 10;
+      }
+    }
+    Double[] frequenciesArray = frequencies.toArray(new Double[frequencies.size()]);
+    double[] frequenciesPrimitiveArray = new double[frequenciesArray.length];
+    for (int i = 0; i < frequenciesArray.length; i++) {
+      frequenciesPrimitiveArray[i] = frequenciesArray[i];
+    }
+    return frequenciesPrimitiveArray;
+  }
+
+  /**
+   * Fisher-Yates shuffle.
+   */
+  private static int[] order() {
+    int[] order = new int[REPETITIONS * PIP_NUM];
+    long seed = 0;
+    Random generator = new Random(seed);
+    for (int i = 0; i < REPETITIONS * PIP_NUM; i++) {
+      int j = generator.nextInt(i + 1);
+      order[i] = order[j];
+      order[j] = i;
+    }
+    return order;
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
new file mode 100644
index 0000000..01eb4b0
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.PopupWindow;
+import android.widget.TextView;
+import java.util.Arrays;
+
+import com.androidplot.xy.SimpleXYSeries;
+import com.androidplot.xy.XYSeries;
+import com.androidplot.xy.*;
+
+public class HifiUltrasoundTestActivity extends PassFailButtons.Activity {
+
+    public enum Status {
+        START, RECORDING, DONE, PLAYER
+    }
+
+    private static final String TAG = "HifiUltrasoundTestActivity";
+
+    private Status status = Status.START;
+    private TextView info;
+    private Button playerButton;
+    private Button recorderButton;
+    private AudioTrack audioTrack;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.hifi_ultrasound);
+        setInfoResources(R.string.hifi_ultrasound_test, R.string.hifi_ultrasound_test_info, -1);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+
+        Common.setSampleRate(AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC));
+
+        info = (TextView) findViewById(R.id.info_text);
+        info.setMovementMethod(new ScrollingMovementMethod());
+        info.setText(R.string.hifi_ultrasound_test_instruction1);
+
+        final AudioRecordHelper audioRecorder = AudioRecordHelper.getInstance();
+        final int recordRate = audioRecorder.getSampleRate();
+
+        recorderButton = (Button) findViewById(R.id.recorder_button);
+        recorderButton.setOnClickListener(new View.OnClickListener() {
+          private WavAnalyzerTask wavAnalyzerTask = null;
+          private void stopRecording() {
+            audioRecorder.stop();
+            playerButton.setText(R.string.hifi_ultrasound_test_playback);
+            playerButton.setEnabled(true);
+            wavAnalyzerTask = new WavAnalyzerTask(audioRecorder.getByte());
+            wavAnalyzerTask.execute();
+            status = Status.DONE;
+          }
+          @Override
+          public void onClick(View v) {
+            switch (status) {
+
+              case START:
+                info.append("Recording at " + recordRate + "Hz using ");
+                final int source = audioRecorder.getAudioSource();
+                switch (source) {
+                  case 1:
+                    info.append("MIC");
+                    break;
+                  case 6:
+                    info.append("VOICE_RECOGNITION");
+                    break;
+                  default:
+                    info.append("UNEXPECTED " + source);
+                    break;
+                }
+                info.append("\n");
+                status = Status.RECORDING;
+                playerButton.setEnabled(false);
+                recorderButton.setEnabled(false);
+                audioRecorder.start();
+
+                final View finalV = v;
+                new Thread() {
+                  @Override
+                  public void run() {
+                    Double recordingDuration_millis = new Double(1000 * (2.5 +
+                        Common.PREFIX_LENGTH / Common.getSampleRate() +
+                        Common.PAUSE_BEFORE_PREFIX_DURATION_S +
+                        Common.PAUSE_AFTER_PREFIX_DURATION_S +
+                        Common.PIP_NUM * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S)
+                        * Common.REPETITIONS));
+                    Log.d(TAG, "Recording for " + recordingDuration_millis + "ms");
+                    try {
+                      Thread.sleep(recordingDuration_millis.intValue());
+                    } catch (InterruptedException e) {
+                      throw new RuntimeException(e);
+                    }
+                    runOnUiThread(new Runnable() {
+                      @Override
+                      public void run() {
+                        stopRecording();
+                      }
+                    });
+                  }
+                }.start();
+
+                break;
+
+              case DONE:
+                plotResponse(wavAnalyzerTask);
+                break;
+
+              default: break;
+            }
+          }
+        });
+
+        playerButton = (Button) findViewById(R.id.player_button);
+        playerButton.setOnClickListener(new View.OnClickListener() {
+          @Override
+          public void onClick(View v) {
+            switch (status) {
+              case START:
+                playerButton.setEnabled(false);
+                recorderButton.setEnabled(false);
+                status = Status.PLAYER;
+                play();
+                break;
+              default:
+                play(audioRecorder.getByte(), recordRate);
+                break;
+            }
+          }
+        });
+    }
+
+
+    private void plotResponse(WavAnalyzerTask wavAnalyzerTask) {
+      LayoutInflater layoutInflater
+          = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
+      View popupView = layoutInflater.inflate(R.layout.hifi_ultrasound_popup, null);
+      final PopupWindow popupWindow = new PopupWindow(
+          popupView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+
+      Button dismissButton = (Button)popupView.findViewById(R.id.dismiss);
+      dismissButton.setOnClickListener(new Button.OnClickListener(){
+        @Override
+        public void onClick(View v) {
+          popupWindow.dismiss();
+          recorderButton.setEnabled(true);
+        }});
+      popupWindow.showAtLocation(info, Gravity.CENTER, 0, 0);
+
+      recorderButton.setEnabled(false);
+
+      XYPlot plot = (XYPlot) popupView.findViewById(R.id.responseChart);
+      plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 2000);
+
+      Double[] frequencies = new Double[Common.PIP_NUM];
+      for (int i = 0; i < Common.PIP_NUM; i++) {
+        frequencies[i] = new Double(Common.FREQUENCIES_ORIGINAL[i]);
+      }
+
+      if (wavAnalyzerTask != null) {
+
+        double[][] power = wavAnalyzerTask.getPower();
+        for(int i = 0; i < Common.REPETITIONS; i++) {
+          Double[] powerWrap = new Double[Common.PIP_NUM];
+          for (int j = 0; j < Common.PIP_NUM; j++) {
+            powerWrap[j] = new Double(10 * Math.log10(power[j][i]));
+          }
+          XYSeries series = new SimpleXYSeries(
+              Arrays.asList(frequencies),
+              Arrays.asList(powerWrap),
+              "");
+          LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+          seriesFormat.configure(getApplicationContext(),
+              R.xml.ultrasound_line_formatter_trials);
+          seriesFormat.setPointLabelFormatter(null);
+          plot.addSeries(series, seriesFormat);
+        }
+
+        double[] noiseDB = wavAnalyzerTask.getNoiseDB();
+        Double[] noiseDBWrap = new Double[Common.PIP_NUM];
+        for (int i = 0; i < Common.PIP_NUM; i++) {
+          noiseDBWrap[i] = new Double(noiseDB[i]);
+        }
+
+        XYSeries noiseSeries = new SimpleXYSeries(
+            Arrays.asList(frequencies),
+            Arrays.asList(noiseDBWrap),
+            "background noise");
+        LineAndPointFormatter noiseSeriesFormat = new LineAndPointFormatter();
+        noiseSeriesFormat.configure(getApplicationContext(),
+            R.xml.ultrasound_line_formatter_noise);
+        noiseSeriesFormat.setPointLabelFormatter(null);
+        plot.addSeries(noiseSeries, noiseSeriesFormat);
+
+        double[] dB = wavAnalyzerTask.getDB();
+        Double[] dBWrap = new Double[Common.PIP_NUM];
+        for (int i = 0; i < Common.PIP_NUM; i++) {
+          dBWrap[i] = new Double(dB[i]);
+        }
+
+        XYSeries series = new SimpleXYSeries(
+            Arrays.asList(frequencies),
+            Arrays.asList(dBWrap),
+            "median");
+        LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+        seriesFormat.configure(getApplicationContext(),
+            R.xml.ultrasound_line_formatter_median);
+        seriesFormat.setPointLabelFormatter(null);
+        plot.addSeries(series, seriesFormat);
+
+        Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
+        Double[] passY = new Double[] {wavAnalyzerTask.getThreshold(), wavAnalyzerTask.getThreshold()};
+        XYSeries passSeries = new SimpleXYSeries(
+            Arrays.asList(passX), Arrays.asList(passY), "passing");
+        LineAndPointFormatter passSeriesFormat = new LineAndPointFormatter();
+        passSeriesFormat.configure(getApplicationContext(),
+            R.xml.ultrasound_line_formatter_pass);
+        passSeriesFormat.setPointLabelFormatter(null);
+        plot.addSeries(passSeries, passSeriesFormat);
+      }
+    }
+
+    /**
+     * Plays the generated pips.
+     */
+    private void play() {
+      play(SoundGenerator.getInstance().getByte(), Common.getSampleRate());
+    }
+
+    /**
+     * Plays the sound data.
+     */
+    private void play(byte[] data, int sampleRate) {
+      if (audioTrack != null) {
+        audioTrack.stop();
+        audioTrack.release();
+      }
+      audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
+          sampleRate, AudioFormat.CHANNEL_OUT_MONO,
+          AudioFormat.ENCODING_PCM_16BIT, Math.max(data.length, AudioTrack.getMinBufferSize(
+          sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT)),
+          AudioTrack.MODE_STATIC);
+      audioTrack.write(data, 0, data.length);
+      audioTrack.play();
+    }
+
+  /**
+   * AsyncTask class for the analyzing.
+   */
+  private class WavAnalyzerTask extends AsyncTask<Void, String, String>
+      implements WavAnalyzer.Listener {
+
+    private static final String TAG = "WavAnalyzerTask";
+    WavAnalyzer wavAnalyzer;
+
+    public WavAnalyzerTask(byte[] recording) {
+      wavAnalyzer = new WavAnalyzer(recording, AudioRecordHelper.getInstance().getSampleRate(),
+          WavAnalyzerTask.this);
+    }
+
+    double[] getDB() {
+      return wavAnalyzer.getDB();
+    }
+
+    double[][] getPower() {
+      return wavAnalyzer.getPower();
+    }
+
+    double[] getNoiseDB() {
+      return wavAnalyzer.getNoiseDB();
+    }
+
+    double getThreshold() {
+      return wavAnalyzer.getThreshold();
+    }
+
+    @Override
+    protected String doInBackground(Void... params) {
+      boolean result = wavAnalyzer.doWork();
+      if (result) {
+        return getString(R.string.hifi_ultrasound_test_pass);
+      }
+      return getString(R.string.hifi_ultrasound_test_fail);
+    }
+
+    @Override
+    protected void onPostExecute(String result) {
+      info.append(result);
+      recorderButton.setEnabled(true);
+      if (wavAnalyzer.getResult()) {
+        getPassButton().setEnabled(true);
+      }
+      recorderButton.setText(R.string.hifi_ultrasound_test_plot);
+    }
+
+    @Override
+    protected void onProgressUpdate(String... values) {
+      for (String message : values) {
+        info.append(message);
+        Log.d(TAG, message);
+      }
+    }
+
+    @Override
+    public void sendMessage(String message) {
+      publishProgress(message);
+    }
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java
new file mode 100644
index 0000000..f7318ed
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java
@@ -0,0 +1,81 @@
+package com.android.cts.verifier.audio;
+
+/**
+ * Sound generator.
+ */
+public class SoundGenerator {
+
+  private static SoundGenerator instance;
+
+  private final byte[] generatedSound;
+  private final double[] sample;
+
+  private SoundGenerator() {
+    // Initialize sample.
+    int pipNum = Common.PIP_NUM;
+    int prefixTotalLength = Common.PREFIX.length
+        + Util.toLength(Common.PAUSE_BEFORE_PREFIX_DURATION_S, Common.getSampleRate())
+        + Util.toLength(Common.PAUSE_AFTER_PREFIX_DURATION_S, Common.getSampleRate());
+    int repetitionLength = pipNum * Util.toLength(
+        Common.PIP_DURATION_S + Common.PAUSE_DURATION_S, Common.getSampleRate());
+    int sampleLength = prefixTotalLength + Common.REPETITIONS * repetitionLength;
+    sample = new double[sampleLength];
+
+    // Fill sample with prefix.
+    System.arraycopy(Common.PREFIX, 0, sample,
+        Util.toLength(Common.PAUSE_BEFORE_PREFIX_DURATION_S, Common.getSampleRate()),
+        Common.PREFIX.length);
+
+    // Fill the sample.
+    for (int i = 0; i < pipNum * Common.REPETITIONS; i++) {
+      double[] pip = getPip(Common.generateWindow(), Common.FREQUENCIES[i]);
+      System.arraycopy(pip, 0, sample,
+          prefixTotalLength + i * Util.toLength(
+              Common.PIP_DURATION_S + Common.PAUSE_DURATION_S, Common.getSampleRate()),
+          pip.length);
+    }
+
+    // Convert sample to byte.
+    generatedSound = new byte[2 * sample.length];
+    int i = 0;
+    for (double dVal : sample) {
+      short val = (short) ((dVal * 32767));
+      generatedSound[i++] = (byte) (val & 0x00ff);
+      generatedSound[i++] = (byte) ((val & 0xff00) >>> 8);
+    }
+  }
+
+  public static SoundGenerator getInstance() {
+    if (instance == null) {
+      instance = new SoundGenerator();
+    }
+    return instance;
+  }
+
+  /**
+   * Gets a pip sample.
+   */
+  private static double[] getPip(double[] window, double frequency) {
+    int pipArrayLength = window.length;
+    double[] pipArray = new double[pipArrayLength];
+    double radPerSample = 2 * Math.PI / (Common.getSampleRate() / frequency);
+    for (int i = 0; i < pipArrayLength; i++) {
+      pipArray[i] = window[i] * Math.sin(i * radPerSample);
+    }
+    return pipArray;
+  }
+
+  /**
+   * Get generated sound in byte[].
+   */
+  public byte[] getByte() {
+    return generatedSound;
+  }
+
+  /**
+   * Get sample in double[].
+   */
+  public double[] getSample() {
+    return sample;
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Util.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/Util.java
new file mode 100644
index 0000000..4ef62d9
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/Util.java
@@ -0,0 +1,152 @@
+package com.android.cts.verifier.audio;
+
+import org.apache.commons.math.complex.Complex;
+import org.apache.commons.math.stat.descriptive.moment.Mean;
+import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
+import org.apache.commons.math.stat.descriptive.rank.Median;
+import org.apache.commons.math.transform.FastFourierTransformer;
+
+/**
+ * This class contains util functions used in the WavAnalyzer.
+ */
+public class Util {
+
+  /**
+   * Convert time in second to sample array length.
+   */
+  public static int toLength(double duration, int sampleRate) {
+    return (int) Math.round(duration * sampleRate);
+  }
+
+  /**
+   * Calculate mean of data.
+   */
+  public static double mean(double[] data) {
+    Mean mean = new Mean();
+    return mean.evaluate(data);
+  }
+
+  /**
+   * Calculate standard deviation of data.
+   */
+  public static double std(double[] data) {
+    StandardDeviation std = new StandardDeviation();
+    return std.evaluate(data);
+  }
+
+  /**
+   * Calculate median of data.
+   */
+  public static double median(double[] data) {
+    Median median = new Median();
+    median.setData(data);
+    return median.evaluate();
+  }
+
+  /**
+   * Pad zeros at the end, total length of array will be specified as length. If length is smaller
+   * than the length of the data, it returns the data truncated to the length.
+   */
+  public static Complex[] padZeros(Complex[] data, int length) {
+    Complex[] result = new Complex[length];
+    if (length < data.length) {
+      System.arraycopy(data, 0, result, 0, length);
+    } else {
+      System.arraycopy(data, 0, result, 0, data.length);
+      for (int i = data.length; i < result.length; i++) {
+        result[i] = new Complex(0, 0);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Calculate cross correlation using FFT with periodic boundary handling.
+   */
+  public static double[] computeCrossCorrelation(Complex[] data1, Complex[] data2) {
+    FastFourierTransformer fft = new FastFourierTransformer();
+    int n = nextPowerOfTwo(Math.max(data1.length, data2.length));
+    Complex[] data1Fft = fft.transform(padZeros(data1, n));
+    Complex[] data2Fft = fft.transform(padZeros(data2, n));
+    Complex[] dottedData = new Complex[n];
+    for (int i = 0; i < n; i++) {
+      dottedData[i] = data1Fft[i].multiply(data2Fft[i].conjugate());
+    }
+    Complex[] resultComplex = fft.inversetransform(dottedData);
+    double[] resultDouble = new double[resultComplex.length];
+    for (int i = 0; i < resultComplex.length; i++) {
+      resultDouble[i] = resultComplex[i].abs();
+    }
+    return resultDouble;
+  }
+
+  /**
+   * Convert an short array to a double array.
+   */
+  public static double[] toDouble(short[] data) {
+    double[] result = new double[data.length];
+    for (int i = 0; i < data.length; i++) {
+      result[i] = data[i];
+    }
+    return result;
+  }
+
+  /**
+   * Convert a double array to a complex array.
+   */
+  public static Complex[] toComplex(double[] data) {
+    Complex[] result = new Complex[data.length];
+    for (int i = 0; i < data.length; i++) {
+      result[i] = new Complex(data[i], 0.0);
+    }
+    return result;
+  }
+
+  /**
+   * Calculates the next power of 2, greater than or equal to the input positive integer. If the
+   * input is not a positive integer, it returns 1.
+   */
+  public static int nextPowerOfTwo(int n) {
+    return 1 << (32 - Integer.numberOfLeadingZeros(n - 1));
+  }
+
+  /**
+   * Find the index with the max value in an array.
+   */
+  public static int findMaxIndex(double[] data) {
+    return findMaxIndex(data, 0, data.length - 1);
+  }
+
+  /**
+   * Find the index with the max value in a sub-array.
+   */
+  public static int findMaxIndex(double[] data, int startIndex, int endIndex) {
+    int maxIndex = startIndex;
+    for (int i = startIndex + 1; i <= endIndex; i++) {
+      if (data[i] > data[maxIndex]) {
+        maxIndex = i;
+      }
+    }
+    return maxIndex;
+  }
+
+  /**
+   * Returns the index of an array with the array value closest to the desired value.
+   */
+  public static int findClosest(double[] array, double value) {
+    double[] diffArray = new double[array.length];
+    for (int i = 0; i < array.length; i++) {
+      diffArray[i] = Math.abs(value - array[i]);
+    }
+    int index = 0;
+    for (int i = 1; i < array.length; i++) {
+      if (diffArray[i] < diffArray[index]) {
+        index = i;
+        if (diffArray[index] == 0) {
+          break;
+        }
+      }
+    }
+    return index;
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java
new file mode 100644
index 0000000..84d59d6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java
@@ -0,0 +1,264 @@
+package com.android.cts.verifier.audio;
+
+import org.apache.commons.math.complex.Complex;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Class contains the analysis to calculate frequency response.
+ */
+public class WavAnalyzer {
+  private final Listener listener;
+  private final int sampleRate;  // Recording sampling rate.
+  private double[] data;  // Whole recording data.
+  private double[] dB;  // Average response
+  private double[][] power;  // power of each trial
+  private double[] noiseDB;  // background noise
+  private double threshold;  // threshold of passing
+  private boolean result = false;  // result of the test
+
+  /**
+   * Constructor of WavAnalyzer.
+   */
+  public WavAnalyzer(byte[] byteData, int sampleRate, Listener listener) {
+    this.listener = listener;
+    this.sampleRate = sampleRate;
+
+    short[] shortData = new short[byteData.length >> 1];
+    ByteBuffer.wrap(byteData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shortData);
+    this.data = Util.toDouble(shortData);
+    for (int i = 0; i < data.length; i++) {
+      data[i] = data[i] / Short.MAX_VALUE;
+    }
+  }
+
+  /**
+   * Do the analysis. Returns true if passing, false if failing.
+   */
+  public boolean doWork() {
+    if (isClipped()) {
+      return false;
+    }
+    // Calculating the pip strength.
+    listener.sendMessage("Calculating...\n");
+    try {
+      dB = measurePipStrength();
+    } catch (IndexOutOfBoundsException e) {
+      listener.sendMessage("WARNING: May have missed the prefix."
+          + " Turn up the volume or move to a quieter location.\n");
+      return false;
+    }
+    if (!isConsistent()) {
+      return false;
+    }
+    result = responsePassesHifiTest(dB);
+    return result;
+  }
+
+  /**
+   * Check if the recording is clipped.
+   */
+  boolean isClipped() {
+    for (int i = 1; i < data.length; i++) {
+      if ((Math.abs(data[i]) >= Short.MAX_VALUE) && (Math.abs(data[i - 1]) >= Short.MAX_VALUE)) {
+        listener.sendMessage("WARNING: Data is clipped."
+            + " Turn the volume down and redo the procedure.\n");
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Check if the result is consistant across trials.
+   */
+  boolean isConsistent() {
+    double[] coeffOfVar = new double[Common.PIP_NUM];
+    for (int i = 0; i < Common.PIP_NUM; i++) {
+      double[] powerAtFreq = new double[Common.REPETITIONS];
+      for (int j = 0; j < Common.REPETITIONS; j++) {
+        powerAtFreq[j] = power[i][j];
+      }
+      coeffOfVar[i] = Util.std(powerAtFreq) / Util.mean(powerAtFreq);
+    }
+    if (Util.mean(coeffOfVar) > 1.0) {
+      listener.sendMessage("WARNING: Inconsistent result across trials."
+          + " Turn up the volume or move to a quieter location.\n");
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Determine test pass/fail using the frequency response. Package visible for unit testing.
+   */
+  boolean responsePassesHifiTest(double[] dB) {
+    for (int i = 0; i < dB.length; i++) {
+      // Precautionary; NaN should not happen.
+      if (Double.isNaN(dB[i])) {
+        listener.sendMessage(
+            "WARNING: Unexpected NaN in result. Redo the test.\n");
+        return false;
+      }
+    }
+
+    int indexOf4kHz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 4000.0);
+    double[] responseBelow4kHz = new double[indexOf4kHz];
+    System.arraycopy(dB, 0, responseBelow4kHz, 0, indexOf4kHz);
+    double medianResponseBelow4kHz = Util.median(responseBelow4kHz);
+    double[] noiseBelow4kHz = new double[indexOf4kHz];
+    System.arraycopy(noiseDB, 0, noiseBelow4kHz, 0, indexOf4kHz);
+    double medianNoiseBelow4kHz = Util.median(noiseBelow4kHz);
+    if ((medianResponseBelow4kHz - medianNoiseBelow4kHz) < Common.AUDIBLE_SIGNAL_MIN_STRENGTH_DB) {
+      listener.sendMessage("WARNING: Signal is too weak or background noise is too strong."
+          + " Turn up the volume or move to a quieter location.\n");
+      return false;
+    }
+
+    int indexOf18500Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 18500.0);
+    int indexOf20000Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 20000.0);
+    double[] responseInRange = new double[indexOf20000Hz - indexOf18500Hz];
+    System.arraycopy(dB, indexOf18500Hz, responseInRange, 0, responseInRange.length);
+    if (Util.mean(responseInRange) > threshold) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Calculate the Fourier Coefficient at the pip frequency to calculate the frequency response.
+   * dB relative to background noise.
+   * Package visible for unit testing.
+   */
+  double[] measurePipStrength() {
+    listener.sendMessage("Aligning data\n");
+    final int dataStartI = alignData();
+    final int prefixTotalLength = dataStartI + Common.PREFIX.length
+        + Util.toLength(Common.PAUSE_AFTER_PREFIX_DURATION_S, sampleRate);
+    listener.sendMessage("Done.\n");
+    listener.sendMessage("Prefix starts at " + (double) dataStartI / sampleRate + " s \n");
+    if (dataStartI > Math.round(sampleRate
+          * (Common.PAUSE_BEFORE_PREFIX_DURATION_S + Common.PAUSE_AFTER_PREFIX_DURATION_S))
+        + Common.PREFIX_LENGTH) {
+      listener.sendMessage("WARNING: Unexpected prefix start time. May have missed the prefix."
+          + " Turn up the volume or move to a quieter location.\n");
+    }
+
+    double[] noisePoints = new double[Common.window().length];
+    System.arraycopy(data, dataStartI - noisePoints.length - 1, noisePoints, 0, noisePoints.length);
+    for (int j = 0; j < noisePoints.length; j++) {
+      noisePoints[j] = noisePoints[j] * Common.window()[j];
+    }
+
+    noiseDB = new double[Common.PIP_NUM];
+    listener.sendMessage("Analyzing noise strength...\n");
+    for (int i = 0; i < Common.PIP_NUM; i++) {
+      double freq = Common.FREQUENCIES_ORIGINAL[i];
+      Complex fourierCoeff = new Complex(0, 0);
+      final Complex rotator = new Complex(0,
+          -2.0 * Math.PI * freq / sampleRate).exp();
+      Complex phasor = new Complex(1, 0);
+      for (int j = 0; j < noisePoints.length; j++) {
+        fourierCoeff = fourierCoeff.add(phasor.multiply(noisePoints[j]));
+        phasor = phasor.multiply(rotator);
+      }
+      fourierCoeff = fourierCoeff.multiply(1.0 / noisePoints.length);
+      double noisePower = fourierCoeff.multiply(fourierCoeff.conjugate()).abs();
+      noiseDB[i] = 10 * Math.log10(noisePower);
+    }
+
+    int indexOf18500Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 18500.0);
+    int indexOf20000Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 20000.0);
+    double[] noiseInRange = new double[indexOf20000Hz - indexOf18500Hz + 1];
+    System.arraycopy(noiseDB, indexOf18500Hz, noiseInRange, 0, indexOf20000Hz - indexOf18500Hz + 1);
+    double medianNoiseInRange = Util.median(noiseInRange);
+    double stdNoiseInRange = Util.std(noiseInRange);
+    threshold = medianNoiseInRange + Common.ULTRASOUND_SIGNAL_MIN_STRENGTH_RATIO * stdNoiseInRange;
+
+    listener.sendMessage("Analyzing pips...\n");
+    power = new double[Common.PIP_NUM][Common.REPETITIONS];
+    for (int i = 0; i < Common.PIP_NUM * Common.REPETITIONS; i++) {
+      if (i % Common.PIP_NUM == 0) {
+        listener.sendMessage("#" + (i / Common.PIP_NUM + 1) + "\n");
+      }
+
+      int pipExpectedStartI;
+      pipExpectedStartI = prefixTotalLength
+          + Util.toLength(i * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S), sampleRate);
+      // Cut out the data points for the current pip.
+      double[] pipPoints = new double[Common.window().length];
+      System.arraycopy(data, pipExpectedStartI, pipPoints, 0, pipPoints.length);
+      for (int j = 0; j < Common.window().length; j++) {
+        pipPoints[j] = pipPoints[j] * Common.window()[j];
+      }
+      Complex fourierCoeff = new Complex(0, 0);
+      final Complex rotator = new Complex(0,
+          -2.0 * Math.PI * Common.FREQUENCIES[i] / sampleRate).exp();
+      Complex phasor = new Complex(1, 0);
+      for (int j = 0; j < pipPoints.length; j++) {
+        fourierCoeff = fourierCoeff.add(phasor.multiply(pipPoints[j]));
+        phasor = phasor.multiply(rotator);
+      }
+      fourierCoeff = fourierCoeff.multiply(1.0 / pipPoints.length);
+      int j = Common.ORDER[i];
+      power[j % Common.PIP_NUM][j / Common.PIP_NUM] =
+          fourierCoeff.multiply(fourierCoeff.conjugate()).abs();
+    }
+
+    // Calculate median of trials.
+    double[] dB = new double[Common.PIP_NUM];
+    for (int i = 0; i < Common.PIP_NUM; i++) {
+      dB[i] = 10 * Math.log10(Util.median(power[i]));
+    }
+    return dB;
+  }
+
+  /**
+   * Align data using prefix. Package visible for unit testing.
+   */
+  int alignData() {
+    // Zeropadding samples to add in the correlation to avoid FFT wraparound.
+    final int zeroPad = Common.PREFIX_LENGTH - 1;
+    int fftSize = Util.nextPowerOfTwo(
+        (int) Math.round(sampleRate
+          * (Common.PAUSE_BEFORE_PREFIX_DURATION_S + Common.PAUSE_AFTER_PREFIX_DURATION_S))
+        + Common.PREFIX_LENGTH
+        + zeroPad);
+
+    double[] dataCut = new double[fftSize - zeroPad];
+    System.arraycopy(data, 0, dataCut, 0, fftSize - zeroPad);
+    double[] xCorrDataPrefix = Util.computeCrossCorrelation(
+        Util.padZeros(Util.toComplex(dataCut), fftSize),
+        Util.padZeros(Util.toComplex(Common.PREFIX), fftSize));
+    return Util.findMaxIndex(xCorrDataPrefix);
+  }
+
+  double[] getDB() {
+    return dB;
+  }
+
+  double[][] getPower() {
+    return power;
+  }
+
+  double[] getNoiseDB() {
+    return noiseDB;
+  }
+
+  double getThreshold() {
+    return threshold;
+  }
+
+  boolean getResult() {
+    return result;
+  }
+
+  /**
+   * An interface for listening a message publishing the progress of the analyzer.
+   */
+  public interface Listener {
+
+    void sendMessage(String message);
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/AutoLockTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/AutoLockTest.java
deleted file mode 100644
index 9181b29..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/AutoLockTest.java
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.camera.analyzer;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.ImageFormat;
-import android.hardware.Camera;
-import android.hardware.usb.UsbAccessory;
-import android.hardware.usb.UsbManager;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.view.SurfaceView;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implements a test to verify whether the Auto Exposure Lock functions as
- * described in the API.
- *
- * The test consists three sub-categories. The first set of tests focus on
- * testing whether the auto exposure lock works in various situations.
- * For all tests in this set, the lock is set during the period when the camera
- * preview is open. In this way the lock locks exposure according to the
- * lighting at the moment of setting the lock. The second set of tests focus on
- * testing whether the auto exposure lock works as expected after turning the
- * preview off and on. The lock is set during the period when the camera
- * preview is turned off. The lock is expected to lock an exposure level
- * identical to the one before the preview is turned off. One special case in
- * this category is to set lock before the preview is turned on for the first
- * time.
- */
-public class AutoLockTest extends CameraTests {
-
-    private static final String TAG = "AutoLockTest";
-    /** USB permission to connect to ADK. */
-    private static final String ACTION_USB_PERMISSION = "com.android.cts.verifier.USB_PERMISSION";
-    /** Defines a long sleep period.*/
-    private static final int SHORT_SLEEP = 2000;
-    /** Defines a short sleep period. */
-    private static final int LONG_SLEEP = 4000;
-
-    /** Test results in text format. */
-    private String mDebugText = new String();
-    /** Detailed report. */
-    private String mResultText = new String();
-    /** Thread lock of the camera callbacks. */
-    private final Object mProcessingImage = new Object();
-    /** Memory address of the native test handler. */
-    private long mTestHandler;
-    /** Array storing the reference test results. */
-    private ArrayList<Boolean> mReferenceCompareResults;
-    /** Array storing the reference test scenario logs. */
-    private ArrayList<String> mReferenceLogs;
-    /** Number of tests so far. */
-    private int mTestCount;
-
-    /** Usb Manager of the USB connections. */
-    private UsbManager mUsbManager;
-    /** Intent for getting the permission to access the ADK. */
-    private PendingIntent mPermissionIntent;
-    /** Boolean to represent whether a permission is gained. */
-    private boolean mPermissionRequestPending;
-    /** USB accessory pointing to the ADK. */
-    private UsbAccessory mAccessory;
-    /** File descriptor of the USB communication port. */
-    private ParcelFileDescriptor mFileDescriptor;
-    /** Output stream to write commands for ADK to. */
-    private FileOutputStream mOutputStream;
-
-    /** Pointer to the CameraAnalyzerActivity activity. */
-    private CameraAnalyzerActivity mActivity;
-    /** Boolean to tell whether the accessory is opened. */
-    private boolean mSetupReady;
-    /** Thread lock for setting up the usb. */
-    private final Object mUsbSetup = new Object();
-    /** Boolean to indicate whether there is an ADK attached. */
-    private boolean mUsingUsb = false;
-    /** Test results.*/
-    private int[] mTestResults;
-    /** Number of tests. */
-    private int mNumTests;
-    /** Singleton test instance.*/
-    private static AutoLockTest singletonTest = null;
-
-    /**
-     * Receives the notice of whether the connection to ADK is granted or
-     * denied.
-     */
-    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            Log.v(TAG, String.format("Received USB broadcast with action %s ", action));
-
-            if (ACTION_USB_PERMISSION.equals(action)) {
-                synchronized (this) {
-                    UsbAccessory accessory =
-                        (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-
-                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
-                        // Grants the permission to connect to the ADK.
-                        Log.v(TAG, "Open accessory 3");
-                        openAccessory(accessory);
-                        // Overwrites the old camera instsance with the one currently opened
-                        // by the CameraAnalyzerActivity instance, since the permission
-                        // dialogue pauses the CameraAnalyzerActivity and forces the camera to
-                        // be released and reopened when the dialogue disappears.
-                        mTestCamera = mActivity.getCameraInstance();
-                    } else {
-                        // Denies the permission to connect to the ADK.
-                        Log.d(TAG, "permission denied for accessory " + accessory);
-                    }
-                    // Marks that the permission request has been processed.
-                    mPermissionRequestPending = false;
-                }
-            } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
-                // Invokes when the USB is detached.
-                // Closes the accessory if it has not been closed.
-                Log.v(TAG, "Usb device detached");
-                mUsingUsb = false;
-                UsbAccessory accessory =
-                    (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-                if (accessory != null && accessory.equals(mAccessory)) {
-                    closeAccessory();
-                }
-            }
-        }
-    };
-
-    /**
-     * Opens the ADK from USB and attaches the output stream with it.
-     *
-     * Notifies the tread lock that the USB setup is ready.
-     */
-    private void openAccessory(UsbAccessory accessory) {
-        Log.d(TAG, "openAccessory: " + accessory);
-        mFileDescriptor = mUsbManager.openAccessory(accessory);
-
-        if (mFileDescriptor != null) {
-            mAccessory = accessory;
-            FileDescriptor fd = mFileDescriptor.getFileDescriptor();
-            mOutputStream = new FileOutputStream(fd);
-            Log.d(TAG, "accessory opened");
-        } else {
-            Log.d(TAG, "accessory open fail");
-        }
-
-        // Unlocks the thread lock of waiting for the USB to be ready.
-        synchronized (mUsbSetup) {
-            mSetupReady = true;
-            Log.v(TAG, "Setup ready");
-            mUsbSetup.notifyAll();
-        }
-    }
-
-    /**
-     * Closes the ADK and detaches the output stream from it.
-     */
-    private void closeAccessory() {
-        try {
-            if (mFileDescriptor != null) {
-                mFileDescriptor.close();
-            }
-        } catch (IOException e) {
-        } finally {
-            mFileDescriptor = null;
-            mAccessory = null;
-        }
-    }
-
-    /**
-     * Constructs the AutoLockTest class, which can execute a series of tests
-     * to verify whether the device's Auto Exposure Lock is working properly.
-     *
-     * The test uses the LED lights on an ADK device as light source to change
-     * the lighting condition of the environment. The usb connection to the
-     * ADK board is established in the constructor.
-     *
-     * @param hostActivity pointer to the <code>CameraAnalyzerActivity</code>
-     * that instructs the Auto Lock Test
-     * @param mCamera pointer to the current camera instance
-     */
-    private AutoLockTest(){
-        super();
-    }
-
-    public static synchronized AutoLockTest getSingletonTest() {
-        if (singletonTest == null) {
-            Log.v(TAG, "Creating a new AutoLockTest instance");
-            singletonTest = new AutoLockTest();
-            singletonTest.initializeTest();
-        }
-        return singletonTest;
-    }
-
-    private void initializeTest() {
-        // Creates a native test handler with a 120x160 pixel debug output
-        mTestHandler = createAutoLockTest();
-        mReferenceCompareResults = new ArrayList<Boolean>();
-        mReferenceLogs = new ArrayList<String>();
-        mNumTests = 4;
-        mTestResults = new int[mNumTests];
-        for (int i = 0; i < mNumTests; ++i) {
-            mTestResults[i] = CameraTests.CAMERA_TEST_NOT_RUN;
-        }
-    }
-
-    public void updateCamera() {}
-
-    public void setActivity(CameraAnalyzerActivity hostActivity){
-        if (mUsingUsb) {
-            closeConnection();
-        }
-
-        mActivity = hostActivity;
-
-        mSetupReady = false;
-
-        Log.v(TAG, "Start to test ADK connection");
-        // Starts to establish the connection to the ADK board.
-        mUsbManager = (UsbManager) mActivity.getSystemService(Context.USB_SERVICE);
-        mPermissionIntent = PendingIntent.getBroadcast(mActivity, 0,
-                                                       new Intent(ACTION_USB_PERMISSION), 0);
-        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
-        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
-        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
-        mActivity.registerReceiver(mUsbReceiver, filter);
-
-        if (mActivity.getLastNonConfigurationInstance() != null) {
-            mAccessory = (UsbAccessory) mActivity.getLastNonConfigurationInstance();
-            Log.v(TAG, "Open acceossory 1");
-            openAccessory(mAccessory);
-        }
-
-        // Skips the permission listener if the user already grants the ADK
-        // permission previously in the app.
-        UsbAccessory[] accessories = mUsbManager.getAccessoryList();
-        UsbAccessory accessory = (accessories == null ? null : accessories[0]);
-        if (accessory != null) {
-            if (mUsbManager.hasPermission(accessory)) {
-                Log.v(TAG, "Open accessory 2");
-                openAccessory(accessory);
-            } else {
-                synchronized (mUsbReceiver) {
-                    if (!mPermissionRequestPending) {
-                        mUsbManager.requestPermission(accessory, mPermissionIntent);
-                        mPermissionRequestPending = true;
-                    }
-                }
-            }
-            mUsingUsb = true;
-        } else {
-            Log.d(TAG, "accessory is null");
-            mUsingUsb = false;
-        }
-
-    }
-
-    /**
-     * Closes the accessories and unregister the USB listener at the end of
-     * tests.
-     */
-    public void closeConnection() {
-        closeAccessory();
-        mActivity.unregisterReceiver(mUsbReceiver);
-    }
-
-    protected void finalize ()  {
-        if (mUsingUsb) {
-            closeConnection();
-        }
-    }
-
-    /**
-     * Runs the Auto Lock tests. A total of 19 tests have been coded and
-     * included. Developers can freely comment out tests not interested. In
-     * the release version, all tests will be executed.
-     */
-    @Override
-    public synchronized void run(int index){
-        if (index == 0) {
-            for (int i = 1; i < mNumTests; ++i) {
-                run(i);
-            }
-            return;
-        }
-
-        Log.v(TAG, "AutoLockTest thread started!");
-
-        if (mUsingUsb && (!mSetupReady)) {
-            // USB connection is not set up. Locks thread and wait.
-            Log.v(TAG, "Setup not ready, waiting");
-            synchronized (mUsbSetup) {
-                try{
-                    Log.v(TAG, "Start waiting for Image");
-                    mUsbSetup.wait();
-                } catch (InterruptedException e) {
-                    Log.v(TAG, "Callback wait fails!");
-                }
-            }
-        }
-
-        // Restarts the camera intance and attach the preview to the corrent
-        // UI elements.
-        restartCamera();
-        startPreview();
-
-        mTestCount = 0;
-        switch (index) {
-            case 1:
-                Log.v(TAG, "SP -> TP1 -> SP -> +1 -> Lock -> -1 -> TP2");
-                test0();
-                Log.v(TAG, "SP -> TP1 -> SP -> Lock -> +1 -> TP2 -> -1");
-                test1();
-                Log.v(TAG, "SP -> Lock -> +1 -> TP1 -> SP -> -1 -> Lock -> TP2");
-                test2();
-                Log.v(TAG, "SP -> Lock -> +1 -> TP1 -> SP -> Lock -> -1 -> TP2");
-                test3();
-                break;
-            case 2:
-                Log.v(TAG, "SP -> +1 -> TP1 -> -1 -> Lock -> SP -> TP2");
-                test4();
-                Log.v(TAG, "SP -> +1 -> TP1 -> Lock -> SP -> -1 -> TP2");
-                test5();
-                Log.v(TAG, "SP -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2");
-                test6();
-                Log.v(TAG, "SP -> TP1 -> +1 -> Lock -> SP -> TP2");
-                test7();
-                Log.v(TAG, "SP -> TP1 -> Lock -> SP -> +1 -> TP2");
-                test8();
-                Log.v(TAG, "SP -> +1 -> Lock -> -1 -> TP1 -> Lock -> SP -> TP2");
-                test9();
-                Log.v(TAG, "SP -> +1 -> Lock -> TP1 -> -1 -> Lock -> SP -> TP2");
-                test10();
-                Log.v(TAG, "SP -> Lock -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2");
-                test11();
-                break;
-            case 3:
-                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> Restart -> Lock -> SP -> +1 -> TP2");
-                test12();
-                Log.v(TAG, "Restart -> Lock -> SP -> +1 -> TP1 -> -1 -> Lock -> SP -> TP2");
-                test13();
-                Log.v(TAG, "Restart -> Lock -> SP -> +1 -> TP1 -> Lock -> SP -> -1 -> TP2");
-                test14();
-                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2");
-                test15();
-                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> TP2");
-                test16();
-                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> Lock -> SP -> +1 -> TP2");
-                test17();
-                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> Lock -> SP -> TP2");
-                test18();
-                break;
-            default:
-                break;
-        }
-
-        releaseLock();
-
-        Log.v(TAG, "Ready to process data");
-        boolean[] testCompareResults = new boolean[2 * mTestCount];
-
-        // Processes the data stored in the native test handler instance.
-        // Stores the test results into a boolean array.
-        processAutoLockTest(mTestHandler, testCompareResults);
-
-        // Prepares the test result text output with the booelan result array.
-        prepareDebugText(testCompareResults, index);
-        mReferenceCompareResults.clear();
-        mReferenceLogs.clear();
-    }
-
-    /**
-     * Compares two images taken under the same lighting, Image 1 without AE
-     * lock and Image 2 with AE locked under a bright light. Image 1 is
-     * expected to be brighter than Image 2.
-     * Tests whether AE lock works compared to no AE lock.
-     */
-    private void test0() {
-        releaseLock();
-        takePicture();
-        startPreview();
-        turnOnLight();
-        setLock();
-        turnOffLight();
-        takePicture();
-        startPreview();
-        releaseLock();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Same lighting condition with one different lock");
-        ++mTestCount;
-    }
-
-    /**
-     * Compares two images taken under different lighting, Image 1 without AE
-     * lock and Image 2 with with AE locked under the same light Image 1 is
-     * taken. Image 2 is taken under a bright light. Image 1 is expected to be
-     * darker than Image 2.
-     * Tests whether AE lock works compared to no AE lock.
-     */
-    private void test1() {
-        releaseLock();
-        takePicture();
-        startPreview();
-        setLock();
-        turnOnLight();
-        takePicture();
-        turnOffLight();
-        startPreview();
-        releaseLock();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("One same lock with different lighting");
-        ++mTestCount;
-    }
-
-    /**
-     * Compares two images taken under different light, both with AE locked
-     * under the same lighting. Image 1 is taken under a brighter light.
-     * Image 1 is expected to be brighter than Image 2.
-     * Tests whether AE locks the exposure to the same level in the same
-     * lighting condition after preview restarts.
-     */
-     private void test2() {
-        releaseLock();
-        setLock();
-        turnOnLight();
-        takePicture();
-        startPreview();
-        turnOffLight();
-        setLock();
-        takePicture();
-        startPreview();
-        releaseLock();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Same locking locations with different lighting");
-        ++mTestCount;
-    }
-
-    /**
-     * Compares two images taken under different light, Image 1 with AE locked
-     * under normal light and Image 2 with AE locked under a bright light.
-     * Image 1 is taken under a bright light and Image 2 is taken in the normal
-     * lighting. Image 1 is expected to be brighter than Image 2.
-     * Tests whether AE lock can adjust to change of lighting conditions.
-     */
-    private void test3() {
-        releaseLock();
-        setLock();
-        turnOnLight();
-        takePicture();
-        startPreview();
-        setLock();
-        turnOffLight();
-        takePicture();
-        startPreview();
-        releaseLock();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Different locking locations with different lighting");
-        ++mTestCount;
-    }
-
-    /**
-     * Compares two images taken under different lighting, Image 1 without
-     * AE lock and Image 2 with AE lock set before camera preview resumes.
-     * Image 1 is taken under a bright light and the light is turned off before
-     * camera preview starts again. Image 1 is expected to be brighter than
-     * Image 2.
-     * Tests whether setting AE lock between camera preview stops and restarts
-     * can retain the exposure level of the previous AE-unlocked photo.
-     */
-    private void test4() {
-        releaseLock();
-        turnOnLight();
-        takePicture();
-        turnOffLight();
-        setLock();
-        startPreview();
-        takePicture();
-        startPreview();
-        releaseLock();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after takePicture and light change, before preview");
-        ++mTestCount;
-    }
-
-    /**
-     * Compares two images taken under different lighting, Image 1 without
-     * AE lock and Image 2 with AE lock set before camera preview resumes.
-     * Image 1 is taken under a bright light and the light is turned off after
-     * preview restars but before Image 2 is taken. Image 1 is expected to be
-     * brighter than Image 2.
-     * Tests whether setting AE lock between camera preview stops and restarts
-     * can retain the exposure level of the previous AE-unlocked photo.
-     */
-    private void test5() {
-        releaseLock();
-        turnOnLight();
-        takePicture();
-        setLock();
-        startPreview();
-        turnOffLight();
-        takePicture();
-        startPreview();
-        releaseLock();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock between takePicture and light change, w/o light change");
-        ++mTestCount;
-    }
-
-    private void test6() {
-        releaseLock();
-        takePicture();
-        turnOnLight();
-        setLock();
-        startPreview();
-        turnOffLight();
-        takePicture();
-        startPreview();
-        releaseLock();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add("Lock after takePicture and light change, before preview.");
-        ++mTestCount;
-    }
-
-    private void test7() {
-        releaseLock();
-        takePicture();
-        turnOnLight();
-        setLock();
-        startPreview();
-        takePicture();
-        startPreview();
-        releaseLock();
-        turnOffLight();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after takePicture and light change, before preview.");
-        ++mTestCount;
-    }
-
-    private void test8() {
-        releaseLock();
-        takePicture();
-        setLock();
-        startPreview();
-        turnOnLight();
-        takePicture();
-        startPreview();
-        releaseLock();
-        turnOffLight();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after takePicture and before startPreview.");
-        ++mTestCount;
-    }
-
-    private void test9() {
-        releaseLock();
-        turnOnLight();
-        setLock();
-        turnOffLight();
-        takePicture();
-        setLock();
-        startPreview();
-        takePicture();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test10() {
-        releaseLock();
-        turnOnLight();
-        setLock();
-        takePicture();
-        turnOffLight();
-        setLock();
-        startPreview();
-        takePicture();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test11() {
-        releaseLock();
-        setLock();
-        takePicture();
-        turnOnLight();
-        setLock();
-        startPreview();
-        turnOffLight();
-        takePicture();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test12() {
-        //"Restart -> Lock -> SP -> TP1 -> Restart -> Lock -> SP -> +1 -> TP2"
-        restartCamera();
-        setLock();
-        startPreview();
-        takePicture();
-        releaseLock();
-        restartCamera();
-        setLock();
-        startPreview();
-        turnOnLight();
-        takePicture();
-        releaseLock();
-        turnOffLight();
-        startPreview();
-        //mTestCamera.release();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock before first preview");
-        ++mTestCount;
-    }
-
-    private void test13() {
-        //"Restart -> Lock -> SP -> +1 -> TP1 -> -1 -> Lock -> SP -> TP2"
-        restartCamera();
-        setLock();
-        startPreview();
-        turnOnLight();
-        takePicture();
-        turnOffLight();
-        setLock();
-        startPreview();
-        takePicture();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test14() {
-        //"Restart -> Lock -> SP -> +1 -> TP1 -> Lock -> SP -> -1 -> TP2"
-        restartCamera();
-        setLock();
-        startPreview();
-        turnOnLight();
-        takePicture();
-        setLock();
-        startPreview();
-        turnOffLight();
-        takePicture();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test15() {
-        //"Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2"
-         restartCamera();
-        setLock();
-        startPreview();
-        takePicture();
-        turnOnLight();
-        setLock();
-        startPreview();
-        turnOffLight();
-        takePicture();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test16() {
-        //"Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> TP2"
-        restartCamera();
-        setLock();
-        startPreview();
-        takePicture();
-        turnOnLight();
-        setLock();
-        startPreview();
-        takePicture();
-        turnOffLight();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test17() {
-        //"Restart -> Lock -> SP -> TP1 -> Lock -> SP -> +1 -> TP2"
-        restartCamera();
-        setLock();
-        startPreview();
-        takePicture();
-        setLock();
-        startPreview();
-        turnOnLight();
-        takePicture();
-        turnOffLight();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    private void test18() {
-        //"Restart -> Lock -> SP -> TP1 -> Lock -> SP -> TP2"
-        restartCamera();
-        setLock();
-        startPreview();
-        takePicture();
-        setLock();
-        startPreview();
-        takePicture();
-        releaseLock();
-        startPreview();
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add("Lock after first lock with changing light");
-        ++mTestCount;
-    }
-
-    /**
-     * Restarts the camera by releasing the current instance and get a new
-     * instance. Also connects this new camera instance's preview to the proper
-     * UI surfaceview.
-     */
-    private void restartCamera() {
-        Log.v(TAG, "Restarting Camera");
-
-        mTestCamera.release();
-        Log.v(TAG, "Camera released");
-
-        try {
-            mTestCamera = Camera.open(mActivity.getCameraIdx());
-        } catch (RuntimeException e) {
-            throw new RuntimeException("Failed to open the camera", e);
-        }
-
-        Camera.Parameters params = mTestCamera.getParameters();
-        params.setPictureFormat(ImageFormat.JPEG);
-        params.setPictureSize(640, 480);
-        mTestCamera.setParameters(params);
-
-        try {
-            mTestCamera.setPreviewDisplay(super.getCameraView().getHolder());
-        } catch (IOException e) {
-            throw new RuntimeException("Unable to connect camera to display: " + e);
-        }
-    }
-
-    /**
-     * Starts Camera preview with a delay of 2 seconds to let it adjust to
-     * the lighting condition.
-     */
-    private void startPreview() {
-        mTestCamera.startPreview();
-        try{
-            Log.v(TAG, "Waiting");
-            Thread.sleep(2000);
-            Log.v(TAG, "END Waiting");
-        } catch (InterruptedException e){}
-    }
-
-    /**
-     * Sends command to ADK to turn on all the LED lights to white.
-     * Waits for 4 seconds for the camera to adjust to the new lighting.
-     */
-    private void turnOnLight() {
-        Log.v(TAG, "Turn on light");
-        if (mUsingUsb) {
-            byte[] buffer = new byte[3];
-
-            buffer[0] = (byte) 3;
-            buffer[1] = (byte) 0;
-            buffer[2] = (byte) 1;
-            if (mOutputStream != null && buffer[1] != -1) {
-                try {
-                    mOutputStream.write(buffer);
-                } catch (IOException e) {
-                    Log.e(TAG, "write failed", e);
-                }
-            }
-        } else {
-            mActivity.runOnUiThread(new Runnable() {
-                public void run() {
-                    Toast.makeText(mActivity.getApplicationContext(), "Turn on light!", 4).show();
-
-                }
-            });
-        }
-
-        try{
-            Log.v(TAG, "Waiting, Please Turn on light");
-            Thread.sleep(LONG_SLEEP);
-            Log.v(TAG, "END Waiting");
-        } catch (InterruptedException e){}
-    }
-
-    /**
-     * Sends command to ADK to turn off all LED lights.
-     * Waits for 4 seconds for the camera to adjust to the new lighting.
-     */
-    private void turnOffLight() {
-        Log.v(TAG, "Turn off light");
-        if (mUsingUsb) {
-            byte[] buffer = new byte[3];
-
-            buffer[0] = (byte) 3;
-            buffer[1] = (byte) 0;
-            buffer[2] = (byte) 0;
-            if (mOutputStream != null && buffer[1] != -1) {
-                try {
-                    mOutputStream.write(buffer);
-                } catch (IOException e) {
-                    Log.e(TAG, "write failed", e);
-                }
-            }
-        } else {
-            mActivity.runOnUiThread(new Runnable() {
-                public void run() {
-                    Toast.makeText(mActivity.getApplicationContext(), "Turn off light!", 4).show();
-
-                }
-            });
-        }
-
-        try{
-            Log.v(TAG, "Waiting, Please Turn off light");
-            Thread.sleep(LONG_SLEEP);
-            Log.v(TAG, "END Waiting");
-        } catch (InterruptedException e){}
-    }
-
-    /**
-     * Sets the Auto Exposure Lock.
-     * Waits for 2 seonds for the lock to function.
-     */
-    private void setLock() {
-        Camera.Parameters params = mTestCamera.getParameters();
-
-        params.setAutoExposureLock(true);
-        params.setAutoWhiteBalanceLock(true);
-        mTestCamera.setParameters(params);
-        try{
-            Log.v(TAG, "Waiting to set lock");
-            Thread.sleep(2000);
-            Log.v(TAG, "END Waiting");
-        } catch (InterruptedException e){}
-    }
-
-    /**
-     * Releases the Auto Exposure Lock.
-     * Waits for 4 seconds afterwards for the Auto Exposure to be adjusted
-     * to the lighting condition.
-     */
-    private void releaseLock() {
-        Camera.Parameters params = mTestCamera.getParameters();
-
-        params.setAutoExposureLock(false);
-        params.setAutoWhiteBalanceLock(false);
-        mTestCamera.setParameters(params);
-        try{
-            Log.v(TAG, "Waiting to release lock");
-            Thread.sleep(LONG_SLEEP);
-            Log.v(TAG, "END Waiting");
-        } catch (InterruptedException e){}
-
-    }
-
-    /**
-     * Takes a picture and locks thread until the picture callback finishes.
-     */
-    private void takePicture(){
-        mTestCamera.takePicture(null, null, null, mTestJpegListener);
-
-        synchronized (mProcessingImage) {
-            try{
-                Log.v(TAG, "Start waiting for Image");
-              //  System.gc();
-                mProcessingImage.wait();
-            } catch (InterruptedException e){
-                 Log.v(TAG, "Callback wait fails!");
-            }
-        }
-    }
-
-    /**
-     * Prepare for the result to be shown in the UI. The result for each single
-     * test is shown in green if it matches the reference result. It is shown
-     * in red otherwise.
-     */
-    private void prepareDebugText(boolean[] testCompareResults, int index) {
-        boolean groupTestPassed = true;
-         for (int i = 0; i < mTestCount; ++i) {
-              String testLog;
-              boolean testPassed = true;
-              testLog = mReferenceLogs.get(i);
-              mDebugText += (testLog + "<br/>");
-
-              if (testCompareResults[i * 2] == mReferenceCompareResults.get(i * 2)) {
-                  mDebugText += String.format(
-                      "Picture 1 brighter than Picture 2 is %b \n",
-                      testCompareResults[i * 2]);
-              } else {
-                  mDebugText += String.format(
-                      "Picture 1 brighter than Picture 2 is %b \n",
-                      testCompareResults[i * 2]);
-                  testPassed = false;
-              }
-
-              if (testCompareResults[i * 2 + 1] == mReferenceCompareResults.get(i * 2 + 1)) {
-                  mDebugText += String.format(
-                      "Picture 1 is equivalent to Picture 2 is %b \n",
-                      testCompareResults[i * 2 + 1]);
-              } else {
-                  mDebugText += String.format(
-                      "Picture 1 is equivalent to Picture 2 is %b \n",
-                      testCompareResults[i * 2 + 1]);
-                  testPassed = false;
-              }
-
-              if (testPassed) {
-                  mDebugText += "Test passed! \n";
-              } else {
-                  mDebugText += "Test failed! \n";
-                  groupTestPassed = false;
-              }
-         }
-        if (groupTestPassed) {
-            mTestResults[index] = CameraTests.CAMERA_TEST_SUCCESS;
-        } else {
-            mTestResults[index] = CameraTests.CAMERA_TEST_FAILURE;
-        }
-    }
-
-    /**
-     * Clears the debug text so that new test results can be added.
-     */
-    public void clearDebugText() {
-        mDebugText = "";
-    }
-
-    @Override
-    public String getDebugText() {
-        return mDebugText;
-    }
-
-    @Override
-    public String getResultText() {
-        return mDebugText;
-    }
-
-    @Override
-    public String getTestName() {
-        return "Auto Exposure Lock test: \n";
-    }
-
-    @Override
-    public String getTestName(int index) {
-        switch (index) {
-            case 0:
-                return "Run all tests";
-            case 1:
-                return "Compulsory tests";
-            case 2:
-                return "Recommended tests (preview behavior)";
-            case 3:
-                return "Optional tests (default lock)";
-            default:
-                return "";
-        }
-    }
-
-    @Override
-    public int getResult(int index) {
-        return mTestResults[index];
-    }
-
-    @Override
-    public int getNumTests() {
-        return mNumTests;
-    }
-
-    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
-        public void onPictureTaken(byte[] data, Camera mCamera) {
-            Log.v(TAG, "Shutter pressed down!");
-            Bitmap inputImage;
-
-            // Decodes the camera input data into Bitmap.
-            // Constructs a native image class with the image.
-            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
-            long bufferAddress = findNative(inputImage);
-            Log.v(TAG, "findNative method finishes");
-
-            // Cleans up memory taken by the Bitmap.
-            data = null;
-            inputImage.recycle();
-            inputImage = null;
-            System.gc();
-
-            // Passes data from the native image class to the native
-            // test handler.
-            createAutoLockClass(bufferAddress, mTestHandler,
-                                getCheckerCenter(), getCheckerRadius());
-
-            // Unlocks the thread lock.
-            synchronized (mProcessingImage) {
-                mProcessingImage.notifyAll();
-            }
-        }
-    };
-
-    private native long createAutoLockTest();
-
-    private native void createAutoLockClass(long bufferAddress, long handlerAddress,
-                                            long checkerCenterAddress,
-                                            long checkerRadiusAddress);
-
-    private native void processAutoLockTest(long handlerAddress, boolean[] testCompareResults);
-
-    static {
-        System.loadLibrary("cameraanalyzer");
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
deleted file mode 100644
index 34e8d2d..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.verifier.camera.analyzer;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.ImageFormat;
-import android.hardware.Camera;
-import android.hardware.Camera.CameraInfo;
-import android.hardware.Camera.Size;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.text.Html;
-import android.text.method.ScrollingMovementMethod;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Button;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.content.Context;
-
-import java.io.IOException;
-import java.lang.Thread;
-import java.util.List;
-
-/**
- * Controls the UI activities of the camera quality test app. It is created
- * as soon as the app started. Users can launch different quality tests with
- * the buttons in the UI. This class will manage the threading for different
- * tests. Also it will provide debug output or debug text results for tests.
- */
-public class CameraAnalyzerActivity extends PassFailButtons.Activity {
-
-    private static final String TAG = "CameraAnalyzer";
-    private SurfaceView mCameraView;
-    private ImageView mResultView;
-    private Button mFindCheckerButton;
-    private Button mExposureCompensationButton;
-    private Button mWhiteBalanceButton;
-    private Button mAutoLockButton;
-    private Button mMeteringButton;
-    private ListView mTestList;
-    private TwoColumnAdapter mAdapter;
-
-    private Camera mCamera;
-    private int mCameraIdx = 0;
-    private boolean mIsCameraOpen = false;
-
-    private PowerManager mPowerManager;
-    private PowerManager.WakeLock mWakeLock;
-
-    private boolean mProcessingPicture = false;
-    private boolean mTestInProgress = false;
-    private final Object mProcessingTest = new Object();
-    private CameraTests mCurrentTest = null;
-
-    private long mCheckerCenterAddress;
-    private long mCheckerRadiusAddress;
-
-    private String mResultReport = "";
-    static final String[] TESTS = new String[] {"Test1", "Test2"};
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ca_main);
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.camera_analyzer, R.string.ca_info, -1);
-
-        mFindCheckerButton = (Button) findViewById(R.id.findcheckerboardbutton);
-        mExposureCompensationButton = (Button) findViewById(R.id.exposurecompensationbutton);
-        mWhiteBalanceButton = (Button) findViewById(R.id.whitebalancebutton);
-        mAutoLockButton = (Button) findViewById(R.id.lockbutton);
-        mMeteringButton = (Button) findViewById(R.id.meteringbutton);
-        mCameraView = (SurfaceView) findViewById(R.id.cameraview);
-        mResultView = (ImageView) findViewById(R.id.resultview);
-        mTestList = (ListView) findViewById(R.id.ca_tests);
-        mAdapter = new TwoColumnAdapter(this);
-
-        // Initialize the list view.
-        initializeAdapter();
-        mTestList.setAdapter(mAdapter);
-        mTestList.setOnItemClickListener(mListListener);
-
-        mFindCheckerButton.setOnClickListener(mFindCheckerListener);
-        mExposureCompensationButton.setOnClickListener(mExposureCompensationListener);
-        mWhiteBalanceButton.setOnClickListener(mWhiteBalanceListener);
-        mAutoLockButton.setOnClickListener(mAutoLockListener);
-        mMeteringButton.setOnClickListener(mMeteringListener);
-        mCameraView.getHolder().addCallback(mSurfaceChangeListener);
-
-        // Disables all test buttons except the color checker test one.
-        // They will be enabled after the color checker is located.
-        mExposureCompensationButton.setEnabled(false);
-        mWhiteBalanceButton.setEnabled(false);
-        mAutoLockButton.setEnabled(false);
-        mMeteringButton.setEnabled(false);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        openCamera(mCameraIdx);
-        Camera.Parameters params = mCamera.getParameters();
-        params.setPictureFormat(ImageFormat.JPEG);
-        params.setPictureSize(640, 480);
-        mCamera.setParameters(params);
-        Log.v(TAG, "Set resolution to 640*480");
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        CameraTests.getCamera().release();
-        mIsCameraOpen = false;
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.ca_menu, menu);
-
-        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
-        int cameraCount = Camera.getNumberOfCameras();
-        for (int camIdx = 0; camIdx < cameraCount; ++camIdx) {
-            MenuItem cameraMenuItem = menu.add(0, camIdx, Menu.NONE,
-                                               String.format("Open Camera %d", camIdx));
-        }
-      return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        if (item.getItemId() != mCameraIdx) {
-            mCameraIdx = item.getItemId();
-            new SwitchCameraTask().execute(mCameraIdx);
-        }
-        return false;
-    }
-
-    private class SwitchCameraTask extends AsyncTask<Integer, Void, Void> {
-        @Override
-        protected Void doInBackground(Integer... camIdx) {
-            if (mTestInProgress) {
-                synchronized (mProcessingTest) {
-                    try{
-                        Log.v(TAG, "Waiting for test to finish");
-                        mProcessingTest.wait();
-                    } catch (InterruptedException e){
-                         Log.v(TAG, "test wait fails!");
-                    }
-                }
-            }
-
-            openCamera((int)camIdx[0]);
-            return null;
-        }
-    }
-
-    private synchronized void openCamera(int camIdx) {
-        if (mIsCameraOpen) {
-            CameraTests.getCamera().release();
-            Log.v(TAG, "Releasing the cameratests camera");
-        }
-        try {
-            mCamera = Camera.open(camIdx);
-            mIsCameraOpen = true;
-        } catch (RuntimeException e) {
-            throw new RuntimeException("Failed to open the camera", e);
-        }
-
-        try {
-            mCamera.setPreviewDisplay(mCameraView.getHolder());
-        } catch (IOException e) {
-            throw new RuntimeException("Unable to connect camera to display: " + e);
-        }
-        mCamera.startPreview();
-        CameraTests.setCamera(mCamera);
-
-        ColorCheckerTest.getSingletonTest().updateCamera();
-        WhiteBalanceTest.getSingletonTest().updateCamera();
-        ExposureCompensationTest.getSingletonTest().updateCamera();
-        MeteringTest.getSingletonTest().updateCamera();
-        AutoLockTest.getSingletonTest().updateCamera();
-    }
-
-    public Camera getCameraInstance() {
-        return mCamera;
-    }
-
-    public void disableAll() {
-        mExposureCompensationButton.setEnabled(false);
-        mWhiteBalanceButton.setEnabled(false);
-        mAutoLockButton.setEnabled(false);
-        mMeteringButton.setEnabled(false);
-        mFindCheckerButton.setEnabled(false);
-    }
-
-    public void enableAll() {
-        mExposureCompensationButton.setEnabled(true);
-        mWhiteBalanceButton.setEnabled(true);
-        mAutoLockButton.setEnabled(true);
-        mMeteringButton.setEnabled(true);
-        mFindCheckerButton.setEnabled(true);
-    }
-
-    /**
-     * Provides an abstraction for the Camera tests. The camera tests will
-     * run in the background and the results will be shown in the UI thread
-     * after the tests are processed.
-     */
-    private class DebugOutputProcessingTask extends AsyncTask<Integer,
-                                                              Integer,
-                                                              Integer> {
-        @Override
-        protected Integer doInBackground(Integer... cameraTestIndex) {
-            Log.v(TAG, "Do in Background started!");
-
-            mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
-            mWakeLock = mPowerManager.newWakeLock(
-                    PowerManager.SCREEN_DIM_WAKE_LOCK, "CameraQualityTest");
-            mWakeLock.acquire();
-
-            mTestInProgress = true;
-
-            // Processes the camera tests one by one and publishes their
-            // debug output or debug text results after each test is done.
-            mCurrentTest.run((int)cameraTestIndex[0]);
-            publishProgress(cameraTestIndex);
-
-            Log.v(TAG, "Do in Background thread returns!");
-            return cameraTestIndex[0];
-        }
-
-        @Override
-        protected void onProgressUpdate(Integer... cameraTestIndex) {
-            Log.v(TAG, "Prepare to get debug output!");
-
-            // Copies the debug output image or text results to the UI.
-            mResultView.setImageBitmap(mCurrentTest.getDebugOutput());
-            mResultReport += (mCurrentTest.getTestName() + mCurrentTest.getDebugText());
-            mAdapter.notifyDataSetChanged();
-        }
-
-        @Override
-        protected void onPostExecute(Integer cameraTestIndex) {
-
-            // If the test is to find the color checker, copy the memory
-            // address of the found color checker centers and radius to the
-            // CameraTests class' static fields.
-            if (mCurrentTest.copyCheckerAddress()) {
-                mCheckerCenterAddress = CameraTests.getCheckerCenter();
-                mCheckerRadiusAddress = CameraTests.getCheckerRadius();
-            }
-
-            if (mCurrentTest.copyCheckerAddress() ||
-                !mCurrentTest.getTestName().contains("Color Checker")) {
-                // Enables the button of all other tests after the color checker
-                // is found. Now the user can start all other available tests.
-                enableAll();
-            }
-
-            mWakeLock.release();
-            mTestInProgress = false;
-            synchronized (mProcessingTest) {
-                mProcessingTest.notifyAll();
-            }
-
-        }
-    }
-
-    // Creates and runs a new test to find color checker in the captured image.
-    // It is invoked when users press the Find color checker button in the UI.
-    private View.OnClickListener mFindCheckerListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            Log.v(TAG, "Running new color checker finding tests!");
-            ColorCheckerTest colorCheckerTest = ColorCheckerTest.getSingletonTest();
-
-            mCurrentTest = colorCheckerTest;
-            initializeAdapter();
-        }
-    };
-
-    // Creates and runs a new test to test the exposure compensation function.
-    // It is invoked when users press the Exposure Compensation Test button
-    // in the UI.
-    private View.OnClickListener mExposureCompensationListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            Log.v(TAG, "Running new exposure compensation tests!");
-
-            ExposureCompensationTest exposureCompensationTest =
-                    ExposureCompensationTest.getSingletonTest();
-
-            mCurrentTest = exposureCompensationTest;
-            initializeAdapter();
-
-            // Loads the memory address of the checker centers and radius
-            // from the this class and set the two values for the new test.
-            ExposureCompensationTest.setCheckerAddress(mCheckerCenterAddress,
-                                                   mCheckerRadiusAddress);
-        }
-    };
-
-    // Creates and runs a new test to test the white balance function.
-    // It is invoked when users press the White Balance Test button in the UI.
-    private View.OnClickListener mWhiteBalanceListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            Log.v(TAG, "Running new white balance tests!");
-
-            WhiteBalanceTest whiteBalanceTest = WhiteBalanceTest.getSingletonTest();
-
-            mCurrentTest = whiteBalanceTest;
-            initializeAdapter();
-
-            // Loads the memory address of the checker centers and radius
-            // from the this class and set the two values for the new test.
-            WhiteBalanceTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
-        }
-    };
-
-    // Creates and runs a new test to test the camera metering function.
-    // It is invoked when users press the Metering Test button in the UI.
-    private View.OnClickListener mMeteringListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            Log.v(TAG, "Running new metering tests!");
-
-            MeteringTest meteringTest = MeteringTest.getSingletonTest();
-
-            mCurrentTest = meteringTest;
-            initializeAdapter();
-
-            // Loads the memory address of the checker centers and radius
-            // from the this class and set the two values for the new test.
-            MeteringTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
-        }
-    };
-
-    // Creates and runs new tests to test the camera auto exposure lock.
-    // It is invoked when users press the AWB and AE Lock Test button
-    // in the UI.
-    private View.OnClickListener mAutoLockListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            Log.v(TAG, "Running New auto exposure/wb lock tests!");
-
-            // Loads the memory address of the checker centers and radius
-            // from the this class and set the two values for the new test.
-            AutoLockTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
-
-            // Construct all base case test scenearios for the Auto Lock test.
-            // Detailed documentation on each test can be found in native code.
-            AutoLockTest autoLockTest = AutoLockTest.getSingletonTest();
-            autoLockTest.setActivity(CameraAnalyzerActivity.this);
-
-            mCurrentTest = autoLockTest;
-            initializeAdapter();
-
-        }
-    };
-
-    // Creates a list listner that launches the experiment with the user's click
-    private AdapterView.OnItemClickListener mListListener = new AdapterView.OnItemClickListener() {
-        @Override
-        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            Log.v(TAG, String.format("Item %d selected!", position));
-            if (!mTestInProgress) {
-                DebugOutputProcessingTask captureTask = new DebugOutputProcessingTask();
-                disableAll();
-                captureTask.execute(position);
-            }
-        }
-    };
-
-    private SurfaceHolder.Callback mSurfaceChangeListener =
-            new SurfaceHolder.Callback() {
-
-        // Sets the aspect ratio of the camera preview to 4:3
-        @Override
-        public void surfaceChanged(SurfaceHolder holder,
-                                   int format,
-                                   int width,
-                                   int height) {
-            int x = mCameraView.getWidth();
-            int y = mCameraView.getHeight();
-            Log.v(TAG, String.format("Measures are %d, %d", x, y));
-
-            if ( x > 4.0 / 3.0 * y) {
-                android.view.ViewGroup.LayoutParams lp = mCameraView.getLayoutParams();
-                lp.height =  y;
-                lp.width = (int)(4.0 / 3.0 * lp.height);
-                Log.v(TAG, String.format("params are %d, %d", lp.width, lp.height));
-                mCameraView.setLayoutParams(lp);
-            }
-
-            try {
-                mCamera.setPreviewDisplay(mCameraView.getHolder());
-            } catch (IOException e) {
-                throw new RuntimeException("Unable to connect camera to display: " + e);
-            }
-            CameraTests.setCameraView(mCameraView);
-            mCamera.startPreview();
-        }
-
-        @Override
-        public void surfaceCreated(SurfaceHolder holder) {}
-
-        @Override
-        public void surfaceDestroyed(SurfaceHolder holder) {}
-    };
-
-    @Override
-    public String getTestDetails() {
-        return mResultReport;
-    }
-
-    class TwoColumnAdapter extends ArrayAdapter<String> {
-        TwoColumnAdapter(Context context) {
-            super(context, R.layout.ca_row);
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            LayoutInflater inflater = getLayoutInflater();
-            View row = inflater.inflate(R.layout.ca_row, parent, false);
-            ImageView iconField = (ImageView) row.findViewById(R.id.caTestIcon);
-            TextView nameField = (TextView) row.findViewById(R.id.caTestName);
-            TextView resultField = (TextView) row.findViewById(R.id.caTestResult);
-            if (mCurrentTest != null) {
-                nameField.setText(mCurrentTest.getTestName(position));
-                int result = mCurrentTest.getResult(position);
-                switch (result) {
-                    case CameraTests.CAMERA_TEST_SUCCESS:
-                        resultField.setText("Success");
-                        iconField.setBackgroundColor(Color.rgb(0x99,0xCC,00));
-                        resultField.setTextColor(Color.rgb(0x99,0xCC,00));
-                        break;
-                    case CameraTests.CAMERA_TEST_FAILURE:
-                        resultField.setText("Failed!");
-                        iconField.setBackgroundColor(Color.rgb(0xFF,0x44,0x44));
-                        resultField.setTextColor(Color.rgb(0xFF,0x44,0x44));
-                        break;
-                    case CameraTests.CAMERA_TEST_NOT_RUN:
-                        resultField.setText("Tap to run");
-                        iconField.setBackgroundColor(Color.rgb(0x00,0x99,0xCC));
-                        resultField.setTextColor(Color.rgb(0x33,0xB5,0xE5));
-                        break;
-                }
-            }
-            return row;
-        }
-    }
-
-    private void initializeAdapter() {
-        mAdapter.clear();
-        if (mCurrentTest != null) {
-            for (int i = 0; i < mCurrentTest.getNumTests(); ++i) {
-                mAdapter.add(mCurrentTest.getTestName(i));
-            }
-        }
-    }
-
-    public int getCameraIdx() {
-        return mCameraIdx;
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraTests.java
deleted file mode 100644
index ed99524..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraTests.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.camera.analyzer;
-
-import android.graphics.Bitmap;
-import android.hardware.Camera;
-import android.os.Environment;
-import android.util.Log;
-import android.view.SurfaceView;
-
-import java.io.FileOutputStream;
-import java.io.File;
-import java.lang.Runnable;
-
-/**
- * Provides an abstraction for all camera tests and allows communication
- * between camera test classes with the UI thread. This base class provides
- * functions to contruct and access debug output images. It can access and
- * set the pointer address of checkerboard centers and radius. It also provides
- * native methods to convert an image shot by the camera into a native
- * character array. Another native method it provides is to create a native
- * test handler with desired debug height and width.
- */
-public abstract class CameraTests{
-
-    public static final int CAMERA_TEST_NOT_RUN = 0;
-    public static final int CAMERA_TEST_SUCCESS = 1;
-    public static final int CAMERA_TEST_FAILURE = 2;
-
-    private static final String TAG = "CameraTests";
-
-    /** Memory address of the color checker centers. */
-    private static long sCheckerCenterAddress = 0;
-    /** Memory address of the color checker radius. */
-    private static long sCheckerRadiusAddress = 0;
-    /** The surface view linked with the camera preview. */
-    private static SurfaceView sCameraView;
-    /** Image debug output. */
-    private Bitmap mDebugOutput;
-    /** Shared camera instance. */
-    protected static Camera mTestCamera = null;
-
-    /**
-     * Constructs the base CameraTests class.
-     */
-    public CameraTests() {}
-
-    /**
-     * Returns debug Bitmap image. In the test to find the color checker,
-     * the debug image will be the captured image with a matched color checker
-     * overlay on top. In the exposure compensation test, the debug image
-     * will be the response curve of the camera.
-     * @return A low-resolution Bitmap to be displayed in the UI.
-     */
-    public Bitmap getDebugOutput() {
-        return mDebugOutput;
-    }
-
-    public String getDebugText() {
-        return "";
-    }
-
-    public abstract String getTestName();
-
-    /**
-     * Gets the detailed report for CTS output.
-     */
-    public String getResultText(){
-        return "Details not available \n";
-    }
-
-    /**
-     * Provides a polymorphism to start the run() method for all child classes.
-     */
-    public abstract void run(int index);
-
-    public SurfaceView getCameraView() {
-        return sCameraView;
-    }
-
-    public static void setCameraView(SurfaceView cameraView) {
-        sCameraView = cameraView;
-    }
-
-    /**
-     * Refreshes the camera instance when the activity opens a new camera.
-     */
-    public static void setCamera(Camera newCamera) {
-        mTestCamera = newCamera;
-    }
-
-    public static Camera getCamera() {
-        return mTestCamera;
-    }
-
-    /**
-     * Sets the memory address of the checker centers and checker radius.
-     *
-     * @param inputCenterAddress the new memory address of
-     *                           the color checker centers
-     * @param inputRadiusAddress the new memory address of
-     *                           the color checker radius
-     */
-    public static void setCheckerAddress(long inputCenterAddress, long inputRadiusAddress) {
-        sCheckerCenterAddress = inputCenterAddress;
-        sCheckerRadiusAddress = inputRadiusAddress;
-    }
-
-    /**
-     * Provides polymorphism to indicate whether the checker memory addresses
-     * should be copied.
-     *
-     * @return <code>true</code> if the class invoking the method needs to
-     *                           update the memory address of the color checker
-     *                           centers and radius;
-     *         <code>false</code> if the class invoking the method does NOT
-     *                           update the memory address of the color checker
-     *                           centers and radius.
-     */
-    public boolean copyCheckerAddress() {
-        return false;
-    }
-
-    public void cleanUp() {
-    }
-
-    public static long getCheckerCenter() {
-        return sCheckerCenterAddress;
-    }
-
-    public static long getCheckerRadius() {
-        return sCheckerRadiusAddress;
-    }
-
-    public abstract String getTestName(int index);
-
-    public abstract int getResult(int index);
-
-    public abstract int getNumTests();
-
-    /**
-     * Provides a native method to convert the input Bitmap of the captured
-     * image into a native character array and constructs a native image class
-     * with this character array. This method currently supports conversion
-     * of Bitmaps in the formats of RGB_565 and RGB_8888.
-     *
-     * @param input the input Bitmap, which is decoded from the camrea data.
-     *
-     * @return the memory address of the native image class which contains
-     * the character array.
-     */
-    public native long findNative(Bitmap input);
-
-    /**
-     * Provides a native method to create a native image handler class. The
-     * native image handler class is the base class for all test classes and
-     * contains the debug output as a character array.
-     *
-     * @param outputHeight the desired height for the debug output
-     * @param outputWidth the desired width for the debug output
-     *
-     * @return the memory address of the native test handler class.
-     */
-    public native long createImageTestHandler(int outputHeight, int outputWidth);
-
-    /**
-     * Provides a native method to clean up the memory taken by the handler.
-     *
-     * @param handlerAddress the memory address of the native test handler,
-     * which contains the debug output.
-     */
-    public native void cleanUpHandler(long handlerAddress);
-
-    /**
-     * Provides a native method to convert the native debug output from
-     * character array back to Bitmap and copy it to the debug output of this
-     * class.
-     *
-     * @param handlerAddress the memory address of the native test handler,
-     * which contains the debug output.
-     */
-    public native void displayHandlerDebugOutput(long handlerAddress);
-
-    static {
-        System.loadLibrary("cameraanalyzer");
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorCheckerTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorCheckerTest.java
deleted file mode 100644
index ad171b4..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorCheckerTest.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.camera.analyzer;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.hardware.Camera;
-import android.util.Log;
-import android.widget.ImageView;
-
-import java.util.List;
-
-/** Locates a Xrite Classic Color Checker grid pattern in an image, stores the
- * center positions and the color checker radius, and provides a function to
- * get the memory address of these two properties.
- *
- * The pattern is a 6x4 grid of square color patches. The detection routine
- * assumes the pattern is placed roughly facing the camera, with the long size
- * roughly horizontal. It also assumes that the grey squares are in the bottom
- * row.
- */
-public class ColorCheckerTest extends CameraTests {
-
-    private static final String TAG = "ColorCheckerTest";
-
-    /** Memory address of the image class instance that contains the image. */
-    private long mClassAddress;
-    /** Memory address of the image test class instance. */
-    private long mTestHandler;
-    /** Thread lock. */
-    private final Object mProcessingImage = new Object();
-    /** Boolean to tell whether auto focus has succeded.*/
-    private boolean mAutoFocusSuccess;
-    /** Boolean to tell whether auto focus is supported.*/
-    private boolean mAutoFocusEnabled = false;
-    /** Singleton instance of the class.*/
-    private static ColorCheckerTest singletonTest = null;
-
-    private boolean mFindCheckerSuccess = false;
-    private boolean mHasRunOnce = false;
-
-    /**
-     * Constructs a <code>ColorCheckerTest</code> instance with a given
-     * Camera pointer.
-     */
-    private ColorCheckerTest() {
-        super();
-    }
-
-    /**
-     * Updates the camera and parameter when the activity switches camera.
-     */
-    public void updateCamera() {
-        Camera.Parameters params = mTestCamera.getParameters();
-        List<String> supportedFocusModes = params.getSupportedFocusModes();
-
-        // Sets camera focus mode to Auto focus if it is supported.
-        if (supportedFocusModes.contains(params.FOCUS_MODE_AUTO)) {
-            Log.v(TAG, "Auto focus possible");
-            params.setFocusMode(params.FOCUS_MODE_AUTO);
-            mTestCamera.setParameters(params);
-            mAutoFocusEnabled = true;
-        } else {
-            mAutoFocusEnabled = false;
-        }
-    }
-
-    public static synchronized ColorCheckerTest getSingletonTest() {
-        if (singletonTest == null) {
-            Log.v(TAG, "Creating a new ColorCheckerTest instance");
-            singletonTest = new ColorCheckerTest();
-            singletonTest.initializeTest();
-        }
-        return singletonTest;
-    }
-
-    private void initializeTest() {
-        // Creates a native test handler with a 120x160 pixel debug output
-        mTestHandler = createColorCheckerTest(120, 160);
-    }
-
-    @Override
-    public synchronized void run(int index) {
-        Log.v(TAG, "ColorCheckerTest thread started!");
-        mAutoFocusSuccess = false;
-        mFindCheckerSuccess = false;
-        mHasRunOnce = true;
-        // Sets camera focus mode to Auto focus if it is supported.
-        if (mAutoFocusEnabled) {
-            while (!mAutoFocusSuccess) {
-                // Starts the auto focus process of the camera.
-                mTestCamera.autoFocus(mAutoFocusListener);
-
-                // Locks thread until the camera finishes taking picture.
-                synchronized (mProcessingImage) {
-                    try{
-                        Log.v(TAG, "Start waiting for Image");
-                        mProcessingImage.wait();
-                    } catch (InterruptedException e) {
-                        Log.v(TAG, "Callback wait fails!");
-                    }
-                }
-            }
-        } else {
-            mTestCamera.takePicture(null, null, null, mTestJpegListener);
-            synchronized (mProcessingImage) {
-                try{
-                    Log.v(TAG, "Start waiting for Image");
-                    mProcessingImage.wait();
-                } catch (InterruptedException e) {
-                    Log.v(TAG, "Callback wait fails!");
-                }
-            }
-        }
-
-        // Launches the native method to find the color checker in the image.
-        mFindCheckerSuccess = processColorCheckerTest(mTestHandler);
-        // Displays the debug output from the native test handler instance.
-        displayHandlerDebugOutput(mTestHandler);
-
-        Log.v(TAG, "Callback has returned!");
-    }
-
-    private Camera.AutoFocusCallback mAutoFocusListener = new Camera.AutoFocusCallback() {
-        public void onAutoFocus(boolean mSuccess, Camera mCamera) {
-            if (mSuccess) {
-                mAutoFocusSuccess = true;
-                Log.v(TAG, "Autofocus success!");
-                mCamera.takePicture(null, null, null, mTestJpegListener);
-            } else {
-                try{
-                    Log.v(TAG, "Autofocus failed. Please adjust!");
-                    Thread.sleep(4000);
-                    Log.v(TAG, "END Waiting");
-                } catch (InterruptedException e){}
-
-                synchronized (mProcessingImage) {
-                    mProcessingImage.notifyAll();
-                }
-            }
-        }
-    };
-
-    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
-        public void onPictureTaken(byte[] data, Camera mCamera) {
-            Log.v(TAG, "Shutter pressed down!");
-
-            // Changes the focus mode to fixed to avoid focus shift after
-            // auto focus is successful.
-            //Camera.Parameters params = mCamera.getParameters();
-            //params.setFocusMode(params.FOCUS_MODE_FIXED);
-            //mCamera.setParameters(params);
-
-            // Decodes the camera data to Bitmap and creates a native image
-            // class with the Bitmap.
-            Bitmap inputImage;
-            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
-            long bufferAddress = findNative(inputImage);
-            Log.v(TAG, "findNative method finishes");
-
-            // Cleans up the Bitmap memory space.
-            inputImage.recycle();
-            data = null;
-            inputImage = null;
-            System.gc();
-
-            // Constructs a test handler class to handle the image.
-            createColorCheckerClass(bufferAddress, mTestHandler);
-
-            mCamera.startPreview();
-
-            // Notifies the thread lock the image capture is done.
-            synchronized (mProcessingImage) {
-                mProcessingImage.notifyAll();
-            }
-        }
-    };
-
-    /**
-     * Overrides the base class method and use the memory addresses of the
-     * checker centers and radius computed by the native test handler class
-     * to update the values stored in the base class.
-     *
-     * @return <code>true</code> indicating a memory address upload is needed.
-     */
-    @Override
-    public boolean copyCheckerAddress() {
-        if (mFindCheckerSuccess) {
-            setCheckerAddress(getColorCheckerCenterAdd(mTestHandler),
-                              getColorCheckerRadiusAdd(mTestHandler));
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public void cleanUp() {
-        cleanUpHandler(mTestHandler);
-    }
-
-    @Override
-    public String getTestName() {
-        return "Color Checker test: \n";
-    }
-
-    @Override
-    public String getTestName(int index) {
-        return "Find color checker";
-    }
-
-    @Override
-    public int getResult(int index) {
-        if (mFindCheckerSuccess) {
-            return CameraTests.CAMERA_TEST_SUCCESS;
-        } else {
-            if (mHasRunOnce) {
-                return CameraTests.CAMERA_TEST_FAILURE;
-            } else {
-                return CameraTests.CAMERA_TEST_NOT_RUN;
-            }
-        }
-    }
-
-    @Override
-    public int getNumTests() {
-        return 1;
-    }
-
-    /**
-     * Gets the memory address of the vector storing the color checker centers
-     * from the native test handler instance.
-     *
-     * @param handlerAddress the memory address of the native test handler
-     * instance
-     *
-     * @return memory address of the native vector storing the color checker
-     * centers' coordinates
-     */
-    private native long getColorCheckerRadiusAdd(long handlerAddress);
-
-    /**
-     * Gets the memory address of the vector storing the color checker radius
-     * from the native test handler instance.
-     *
-     * @param handlerAddress the memory address of the native test handler
-     * instance.
-     *
-     * @return memory address of the native vector storing the color checker
-     * centers' coordinates
-     */
-    private native long getColorCheckerCenterAdd(long handlerAddress);
-
-    /**
-     * Creates a native color checker test handler instance.
-     *
-     * @param outputWidth the desired width for the debug output
-     * @param outputHeight the desired height of the debug output
-     *
-     * @return memory address of the native test handler instance
-     */
-    private native long createColorCheckerTest(int outputWidth, int outputHeight);
-
-    /**
-     * Loads a native image class instances and extracts data from it to add
-     * to the test handler.
-     *
-     * @param bufferAddress the memory address of the image class instance
-     * @param handlerAddress the memory address of the test handler instance
-     */
-    private native void createColorCheckerClass(long bufferAddress, long handlerAddress);
-
-    /**
-     * Processes the data in the native test handler instance. Computes test
-     * results with all the data and construct a debug image or debug text
-     * outputs.
-     *
-     * @param handlerAddress the memory address of the test handler instance
-     */
-    private native boolean processColorCheckerTest(long handlerAddress);
-
-    static {
-        System.loadLibrary("cameraanalyzer");
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java
deleted file mode 100644
index 9a8d9f0..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.camera.analyzer;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.ImageFormat;
-import android.hardware.Camera;
-import android.util.Log;
-import android.widget.ImageView;
-
-import java.io.FileOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Random;
-
-public class ExposureCompensationTest extends CameraTests {
-
-    private static final String TAG = "ExposureCompensationTest";
-
-    /** Records the current exposure level. */
-    private float mExposureLevel;
-    /** Lock for the camera object.*/
-    private final Object mProcessingImage = new Object();
-    /** Lock for the camera's auto focusing task.*/
-    private final Object mAutoFocusing = new Object();
-    /** Memory address of the native test handler.*/
-    private long mTestHandler;
-    /** Test results. */
-    private int[] mTestResults;
-    /** Number of sub-tests. */
-    private int mNumTests;
-    /** Camera Parameters. */
-    private Camera.Parameters mParams;
-    /** Debug results in text. */
-    private String mDebugText;
-
-    private static ExposureCompensationTest singletonTest = null;
-
-    private ExposureCompensationTest(){
-        super();
-    }
-
-    /** Prepares the camera and the related parameters for the test.*/
-    public void updateCamera() {
-        mParams = mTestCamera.getParameters();
-        Log.v(TAG, String.format("Exposure level is from %d to %d",
-                                 mParams.getMinExposureCompensation(),
-                                 mParams.getMaxExposureCompensation()));
-        mNumTests = (int) ((float) (mParams.getMaxExposureCompensation() -
-                                    mParams.getMinExposureCompensation())
-                            * mParams.getExposureCompensationStep());
-        mTestResults = new int[mNumTests + 1];
-        for (int i = 0; i < mNumTests + 1; ++i) {
-            mTestResults[i] = CameraTests.CAMERA_TEST_NOT_RUN;
-        }
-    }
-
-    public static synchronized ExposureCompensationTest getSingletonTest() {
-        if (singletonTest == null) {
-            Log.v(TAG, "Creating a new ExposureCompensationTest instance");
-            singletonTest = new ExposureCompensationTest();
-            singletonTest.initializeTest();
-        }
-        return singletonTest;
-    }
-
-    private void initializeTest() {
-        mDebugText = new String();
-        // Creates a native test handler with a 120x160 pixel debug output
-        mTestHandler = createExposureCompensationTest(200, 280);
-    }
-
-    @Override
-    public synchronized void run(int index){
-        Log.v(TAG, "ExposureCompensationTest thread started!");
-
-        int testRangeMin, testRangeMax;
-        if (index == 0) {
-            testRangeMin = mParams.getMinExposureCompensation();
-            testRangeMax = mParams.getMaxExposureCompensation();
-        } else {
-            testRangeMin = (int) ((float)(index - 1) / mParams.getExposureCompensationStep())
-                    + mParams.getMinExposureCompensation();
-            testRangeMax = (int) ((float)(index) / mParams.getExposureCompensationStep())
-                    + mParams.getMinExposureCompensation();
-        }
-
-        /** Checks for each exposure compensation setting within the test range.*/
-        for (int i = testRangeMin;
-                i <= testRangeMax; i += 1){
-            mExposureLevel = i * mParams.getExposureCompensationStep();
-            Log.v(TAG, String.format("Current exposure level is %d", i));
-            int mCameraExposure;
-
-            do{
-                mParams.setExposureCompensation(i);
-                mTestCamera.setParameters(mParams);
-
-                try{
-                    Log.v(TAG, "Waiting");
-                    Thread.sleep(4000);
-                    Log.v(TAG, "END Waiting");
-                } catch (InterruptedException e){
-                    //TODO: error handling.
-                }
-
-                mParams = mTestCamera.getParameters();
-                mCameraExposure = mParams.getExposureCompensation();
-                Log.v(TAG, String.format("Camera exposure level is %d", mCameraExposure));
-            } while (mCameraExposure != i);
-
-            mTestCamera.takePicture(null, null, null, mTestJpegListener);
-
-            synchronized (mProcessingImage) {
-                try{
-                    Log.v(TAG, "Start waiting for Image");
-                    mProcessingImage.wait();
-                } catch (InterruptedException e){
-                    Log.v(TAG, "Callback wait fails!");
-                }
-            }
-        }
-
-        mDebugText = processExposureCompensationTest(mTestHandler);
-        displayHandlerDebugOutput(mTestHandler);
-
-        Log.v(TAG, "Callback has returned!");
-        mParams.setExposureCompensation(0);
-        mTestCamera.setParameters(mParams);
-    }
-
-    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
-        public void onPictureTaken(byte[] data, Camera mCamera) {
-            Log.v(TAG, "Shutter pressed down!");
-            Log.v(TAG, String.format("Current exposure is %f", mExposureLevel));
-
-            Bitmap inputImage;
-
-            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
-            long bufferAddress = findNative(inputImage);
-            Log.v(TAG, "findNative method finishes");
-
-            inputImage.recycle();
-            data = null;
-            inputImage = null;
-            System.gc();
-
-            createExposureCompensationClass(bufferAddress, mTestHandler,
-                                            getCheckerCenter(), getCheckerRadius(),
-                                            mExposureLevel);
-            mCamera.startPreview();
-
-            synchronized (mProcessingImage) {
-                mProcessingImage.notifyAll();
-            }
-        }
-    };
-
-    @Override
-    public String getTestName(int index) {
-        switch (index) {
-            case 0:
-                return "EC All Range";
-            default:
-                return String.format("EC %d -> %d", (index - mNumTests / 2 - 1) * 10,
-                                     (index - mNumTests / 2) * 10);
-        }
-    }
-
-    @Override
-    public int getResult(int index) {
-        return mTestResults[index];
-    }
-
-    @Override
-    public int getNumTests() {
-        return mNumTests + 1;
-    }
-
-    @Override
-    public String getTestName() {
-        return "Exposure Compensation Test: \n";
-    }
-
-    @Override
-    public String getDebugText() {
-        return mDebugText;
-    }
-
-    private native long createExposureCompensationTest(int outputHeight, int outputWidth);
-
-    private native void createExposureCompensationClass(long bufferAddress, long handlerAddress,
-            long checkerCenterAddress, long checkerAadiusAddress, float mExposureLevel);
-
-    private native String processExposureCompensationTest(long handlerAddress);
-
-    static {
-        System.loadLibrary("cameraanalyzer");
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/MeteringTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/MeteringTest.java
deleted file mode 100644
index 9ff559f..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/MeteringTest.java
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.camera.analyzer;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.ImageFormat;
-import android.graphics.Rect;
-import android.hardware.Camera;
-import android.hardware.Camera.Area;
-import android.util.Log;
-import android.widget.ImageView;
-
-import java.io.FileOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * Implements a test to verify whether the camera metering system works as
- * described in the API.
- *
- * The test consists two sub-categories. The first one has tests with only
- * one metering area defined. The second one has tests with two metering areas
- * defined. For each single sub-test, we use a random number generator to
- * decide where to put some of the metering areas to and how much weight should
- * be assigned to each area. For different tests, we use different ways to
- * define other metering areas and their weight, in order to cover all possible
- * fail cases. The metering areas are contrained to the grey squares in the
- * bottom of the color checker.
- */
-public class MeteringTest extends CameraTests {
-
-    private static final String TAG = "MeteringTest";
-
-    /** A long wait.*/
-    private static final int LONG_SLEEP = 4000;
-    /** Debug result in text. */
-    private String mDebugText;
-    /** Thread lock. */
-    private final Object mProcessingImage = new Object();
-    /** Memory address of the native test handler. */
-    private long mTestHandler;
-    /** The maximum number of metering area the device supports. */
-    private int mMaxNumMeteringArea;
-    /** The metering areas. */
-    private List<Camera.Area> mGreyAreas;
-    /** The coordinates of the grey squares on the color checker. */
-    private int[] mGreyCoordinates = new int[24];
-    /** Random number generator. */
-    private final Random mRandomGenerator = new Random();
-    /** Reference comparison result for tests. */
-    private ArrayList<Boolean>  mReferenceCompareResults;
-    /** Number of tests in the same instance. */
-    private int mTestCount;
-    /** Reference test logs. */
-    private ArrayList<String> mReferenceLogs;
-    /** Test result to show. */
-    private int[] mTestResults;
-    /** Number of tests. */
-    private int mNumTests;
-    /** Camera Parameters. */
-    private Camera.Parameters mParams;
-    /** Singleton test instance. */
-    private static MeteringTest singletonTest = null;
-
-    /** Constructs a <code>MeteringTest</code> instance with the given
-     * camera pointer.
-     */
-    private MeteringTest() {
-        super();
-    }
-
-    public void updateCamera() {
-        // Looks up how many metering area the device supports.
-        mParams = mTestCamera.getParameters();
-        mMaxNumMeteringArea = mParams.getMaxNumMeteringAreas();
-        Log.v(TAG, String.format("Maximum number if metering area is %d", mMaxNumMeteringArea));
-        if (mMaxNumMeteringArea == 0) {
-            mDebugText = "Custom Metering not supported!";
-            Log.v(TAG, "Custom Metering not supported");
-        }
-    }
-
-    public static synchronized MeteringTest getSingletonTest() {
-        if (singletonTest == null) {
-            Log.v(TAG, "Creating a new MeteringTest instance");
-            singletonTest = new MeteringTest();
-            singletonTest.initializeTest();
-        }
-        return singletonTest;
-    }
-
-    private void initializeTest() {
-        // Creates a native metering test handler.
-        mTestHandler = createMeteringTest();
-        mDebugText = new String();
-        mReferenceCompareResults = new ArrayList<Boolean>();
-        mReferenceLogs = new ArrayList<String>();
-        mNumTests = 3;
-        mTestResults = new int[mNumTests];
-        for (int i = 0; i < mNumTests; ++i) {
-            mTestResults[i] = CameraTests.CAMERA_TEST_NOT_RUN;
-        }
-    }
-
-    /**
-     * Runs the metering test instance.
-     */
-    @Override
-    public synchronized void run(int index) {
-        if (index == 0) {
-            run(1);
-            run(2);
-            return;
-        }
-        Log.v(TAG, "MeteringTest thread started!");
-
-        // Finds the coordinates of the grey squares on the color checker.
-        // The coordinate system has (-1000, -1000) on the upper left corner.
-        // And (1000, 1000) on the bottom right corner.
-        findGreyCoordinates(mGreyCoordinates, getCheckerCenter(), getCheckerRadius());
-
-        if (mMaxNumMeteringArea > 0) {
-            mTestCount = 0;
-            // Runs the metering tests category by category.
-            switch (index) {
-                case 1:
-                    runOneAreaTest();
-                    break;
-                case 2:
-                    if (mMaxNumMeteringArea > 1) {
-                        runTwoAreasTest();
-                    }
-                    break;
-                default:
-                    break;
-            }
-        }
-
-        mParams = mTestCamera.getParameters();
-        mParams.setMeteringAreas(null);
-        mTestCamera.setParameters(mParams);
-
-        boolean[] testCompareResults = new boolean[2 * mTestCount];
-
-        // Processes the image data taken so far and stores the test results.
-        processMeteringTest(mTestHandler, testCompareResults);
-        // Prepares debug output based on the test results.
-        prepareDebugText(testCompareResults, index);
-
-        mReferenceCompareResults.clear();
-        mReferenceLogs.clear();
-    }
-
-    /**
-     * Prepares the test results in HTML text string to show in the UI.
-     *
-     * If the test result is the same as the reference result, the text will be
-     * shown in green. Otherwise it would be shown as red.
-     *
-     * @param testCompareResults the array storing the comparison results from
-     * the data taken by the camera so far.
-     */
-    private void prepareDebugText(boolean[] testCompareResults, int index) {
-        mDebugText = "";
-        boolean groupTestPassed = true;
-        for (int i = 0; i < mTestCount; ++i) {
-              String testLog;
-              boolean testPassed = true;
-              testLog = mReferenceLogs.get(i);
-              mDebugText += (testLog + "<br/>");
-
-              if (testCompareResults[i * 2] == mReferenceCompareResults.get(i * 2)) {
-                  mDebugText += String.format(
-                      "Picture 1 equivalent to Picture 2 is %b \n",
-                      testCompareResults[i * 2]);
-              } else {
-                  mDebugText += String.format(
-                      "Picture 1 equivalent to Picture 2 is %b \n",
-                      testCompareResults[i * 2]);
-                  testPassed = false;
-              }
-
-              if (testCompareResults[i * 2 + 1] == mReferenceCompareResults.get(i * 2 + 1)) {
-                  mDebugText += String.format(
-                      "Picture 1 darker than Picture 2 is %b \n",
-                      testCompareResults[i * 2 + 1]);
-              } else {
-                  mDebugText += String.format(
-                      "Picture 1 darker than Picture 2 is %b \n",
-                      testCompareResults[i * 2 + 1]);
-                  testPassed = false;
-              }
-
-              if (testPassed) {
-                  mDebugText += "Test passed! \n";
-              } else {
-                  mDebugText += "Test failed! \n";
-                  groupTestPassed = false;
-              }
-              Log.v(TAG, String.format("%s", mDebugText));
-         }
-
-        if (groupTestPassed) {
-            mTestResults[index] = CameraTests.CAMERA_TEST_SUCCESS;
-        } else {
-            mTestResults[index] = CameraTests.CAMERA_TEST_FAILURE;
-        }
-
-    }
-
-    /**
-     * Runs tests to check whether the metering functionalities work properly
-     * when one metering area is added.
-     */
-    private void runOneAreaTest() {
-        int weight1;
-        int weight2;
-        int square1;
-        int square2;
-
-        Log.v(TAG, "Running one area Test");
-
-        // Test case 1: Two images have the same metering area. Image 1 has
-        // a diffent weight than Image 2. The result images should be
-        // identical.
-        // Tests whether weight normalization works.
-        square1 = mRandomGenerator.nextInt(6);
-        weight1 = mRandomGenerator.nextInt(100) + 1;
-        runSingleTest(square1, square1, weight1);
-
-        square2 = square1;
-        weight2 = mRandomGenerator.nextInt(100) + 901;
-        runSingleTest(square2, square2, weight2);
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        Log.v(TAG, String.format("Running test for %d square with weights %d, %d",
-                                 square1, weight1, weight2));
-        mReferenceLogs.add(String.format(
-            "Running test for %d 1x1 square with weights %d, %d", square1, weight1, weight2));
-        ++mTestCount;
-
-        // Test case 2: Two images have different metering areas. Image 1 has
-        // one of the grey squares as its metering area. Image 2 has a darker
-        // grey square as its metering area. The weights for both images are
-        // the same. Image 1 is expected to be darker than Image 2.
-        // Tests whether metering on uni-brightness patches work.
-        square1 = mRandomGenerator.nextInt(5);
-        weight1 = mRandomGenerator.nextInt(1000) + 1;
-        runSingleTest(square1, square1, weight1);
-
-        square2 = mRandomGenerator.nextInt(6 - square1 - 1) + square1 + 1;
-        weight2 = weight1;
-        runSingleTest(square2, square2, weight2);
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add(String.format(
-            "Running test for %d, %d 1x1 square with weight %d", square1, square2, weight1));
-        ++mTestCount;
-
-        // Test case 3: Two images have different metering areas. Image one has
-        // one of the grey squares as its metering area. Image 2 has a
-        // rectangle which contains Image 1's metering area and the neighboring
-        // darker grey square. The weights for both tests are the same. Image 1
-        // is expected to be darker than Image 2.
-        // Tests whether metering on patches with different brightness works.
-        square1 = mRandomGenerator.nextInt(5);
-        weight1 = mRandomGenerator.nextInt(1000) + 1;
-        runSingleTest(square1, square1, weight1);
-
-        square2 = square1;
-        weight2 = weight1;
-        runSingleTest(square2, square2 + 1, weight2);
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add(String.format(
-            "Running test for %d 1x1, 1x2 square with weight %d", square1, weight1));
-        ++mTestCount;
-
-        // Test case 4: Two images have different metering areas. Image one has
-        // two neighboring grey squares as its metering area. Image 2 has two
-        // darker neighboring grey squares as its metering area. Weights are
-        // the same for both images. Image 1 is expected to be darker than
-        // Image 2.
-        // Tests whether metering on two mixed-brightness patches work.
-        square1 = mRandomGenerator.nextInt(4);
-        weight1 = mRandomGenerator.nextInt(1000) + 1;
-        runSingleTest(square1, square1 + 1, weight1);
-
-        square2 = mRandomGenerator.nextInt(5 - square1 - 1) + square1 + 1;
-        weight2 = weight1;
-        runSingleTest(square2, square2 + 1, weight2);
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add(String.format(
-            "Running test for %d, %d 1x2 square with weight %d", square1, square2, weight1));
-        ++mTestCount;
-
-        // Test case 5: Two images have different metering areas. Image one has
-        // three neighboring grey squares as its metering area. Image 2 has
-        // three darker neighboring grey squares as its metering area. Weights
-        // are the same. Image 1 is expected to be darker than Image 2.
-        // Tests whether metering on three mixed-brightness patches work.
-        square1 = mRandomGenerator.nextInt(3);
-        weight1 = mRandomGenerator.nextInt(1000) + 1;
-        runSingleTest(square1, square1 + 2, weight1);
-
-        square2 = mRandomGenerator.nextInt(4 - square1 - 1) + square1 + 1;
-        weight2 = weight1;
-        runSingleTest(square2, square2 + 2, weight2);
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add(String.format(
-            "Running test for %d, %d 1x3 square with weight %d", square1, square2, weight1));
-        ++mTestCount;
-    }
-
-    /**
-     * Runs metering tests to verify the functionalities when there are two
-     * areas set as the metering area.
-     */
-    private void runTwoAreasTest() {
-        int[] weight1 = new int[2];
-        int[] weight2 = new int[2];
-        int[] square1Start = new int[2];
-        int[] square2Start = new int[2];
-        int[] square1End = new int[2];
-        int[] square2End = new int[2];
-
-        Log.v(TAG, "Running two-area Test");
-
-        // Test case 1: Image 1 has two metering areas. They are two adjacent
-        // grey squares (each set as a metering area). The two areas have the
-        // same weight. Image 2 has one metering area, which is the combination
-        // of Image 1's two metering areas as a rectangle. The weight is the
-        // same as that of Image 1's individual area. Image 1 is expected to
-        // be equivalent to Image 2.
-        // Tests whether having seperating a metering area into two will yield
-        // the same result.
-        square1Start[0] = mRandomGenerator.nextInt(5);
-        square1End[0] = square1Start[0];
-        weight1[0] = mRandomGenerator.nextInt(1000) + 1;
-        square1Start[1] = square1Start[0] + 1;
-        square1End[1] = square1Start[1];
-        weight1[1] = weight1[0];
-        runMultipleAreaTest(square1Start, square1End, weight1);
-
-        square2Start[0] = square1Start[0];
-        weight2[0] = weight1[0];
-        runSingleTest(square2Start[0], square2Start[0] + 1, weight2[0]);
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add(String.format(
-            "Running test for %d, %d 1x1 square with weight %d",
-            square1Start[0], square1Start[1], weight1[0]));
-        ++mTestCount;
-
-        // Test case 2: Image 1 has two metering areas. They are two random
-        // grey squareson the color checker. The brighter square has a larger
-        // weight than the darker square. Image 2 has the same two metering
-        // areas as Image 1. The weights for both are equal to the weight of
-        // the darker square in Image 1, which is smaller than the weight of
-        // the brighter square in Image 1. Image 1 is expected to be darker
-        // than Image 2.
-        // Tests whether giving one of the two metering areas a different
-        // weight would change the image in the correct way.
-        square1Start[0] = mRandomGenerator.nextInt(4);
-        square1End[0] = square1Start[0];
-        weight1[0] = mRandomGenerator.nextInt(100) + 901;
-        square1Start[1] = mRandomGenerator.nextInt(5 - square1Start[0] - 1) + square1Start[0] + 1;
-        square1End[1] = square1Start[1];
-        weight1[1] = mRandomGenerator.nextInt(100) + 1;
-        runMultipleAreaTest(square1Start, square1End, weight1);
-
-        square2Start[0] = square1Start[0];
-        square2End[0] = square2Start[0];
-        weight2[0] = weight1[1];
-        square2Start[1] = square1Start[1];
-        square2End[1] = square1End[1];
-        weight2[1] = weight2[0];
-        runMultipleAreaTest(square2Start, square2End, weight2);
-        mReferenceCompareResults.add(false);
-        mReferenceCompareResults.add(true);
-        mReferenceLogs.add(String.format(
-            "Running test for %d, %d 1x1 square with weight %d, %d",
-            square1Start[0], square1Start[1], weight1[0], weight2[1]));
-        ++mTestCount;
-
-        // Test case 3: Image 1 has two metering areas. Both are set to the
-        // same random grey square on the color checker. The weight for both
-        // are the same. Image 2 has one meterig area, which is the same as
-        // Image 1's chosen grey square. The weight for it is the same as
-        // Image 1's weight for one metering area. Image 1 is expected to be
-        // equivalent to Image 2.
-        // Tests whether defining overlapping metering area works.
-        square1Start[0] = mRandomGenerator.nextInt(6);
-        square1End[0] = square1Start[0];
-        weight1[0] = mRandomGenerator.nextInt(1000) + 1;
-        square1Start[1] = square1Start[0];
-        square1End[1] = square1Start[1];
-        weight1[1] = weight1[0];
-        runMultipleAreaTest(square1Start, square1End, weight1);
-
-        square2Start[0] = square1Start[0];
-        square2End[0] = square2Start[0];
-        weight2[0] = weight1[0];
-        runSingleTest(square2Start[0], square2End[0], weight2[0]);
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add(String.format(
-            "Running test for %d 1x1 square with weight %d,", square1Start[0], weight1[0]));
-        ++mTestCount;
-
-        // Test case 4: Image 1 has two metering areas. The first one is a
-        // grey square on the color checker. The second one is a rectangle
-        // containing the first metering area's grey square and its neighboring
-        // darker square. The weights for both metering area are the same.
-        // Image 2 has two metering areas. The first one is the same grey
-        // square as Image 1's first metering area. The second one is the
-        // neighboring darker grey square. The weight for the brighter square
-        // is double the weight of Image 1's weights for each metering area.
-        // The weight for the Image 2's darker grey square is the same as
-        // Image 1's weight for each of its metering areas. Image 1 is expected
-        // to be equivalent to Image 2.
-        // Tests whether the weights for overlapping metering area add up.
-        square1Start[0] = mRandomGenerator.nextInt(2);
-        square1End[0] = square1Start[0];
-        weight1[0] = mRandomGenerator.nextInt(500) + 1;
-        square1Start[1] = square1Start[0];
-        square1End[1] = square1Start[1] + 1;
-        weight1[1] = weight1[0];
-        runMultipleAreaTest(square1Start, square1End, weight1);
-
-        square2Start[0] = square1Start[0];
-        square2End[0] = square1End[0];
-        weight2[0] = weight1[0] * 2;
-        square2Start[1] = square2Start[0] + 1;
-        square2End[1] = square2Start[1];
-        weight2[1] = weight1[1];
-        runMultipleAreaTest(square2Start, square2End, weight2);
-        mReferenceCompareResults.add(true);
-        mReferenceCompareResults.add(false);
-        mReferenceLogs.add(String.format(
-            "Running test for %d 1x2 1x1 and 1x2 square with weight %d,",
-            square1Start[0], weight1[0]));
-        ++mTestCount;
-    }
-
-    /**
-     * Runs the metering test when multiple metering areas are defined.
-     *
-     * @param startIndex the array storing the index of the grey square where
-     * one metering area starts
-     * @param endIndex the array storing the index of the grey square where one
-     * metering area ends.
-     * @param weight the array storing the weight for each metering area.
-     */
-    private void runMultipleAreaTest(int[] startIndex, int[] endIndex, int[] weight) {
-        int numAreas = startIndex.length;
-        mParams = mTestCamera.getParameters();
-        List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
-
-        for (int i = 0; i < numAreas; ++i) {
-            meteringAreas.add(makeArea(startIndex[i], endIndex[i], weight[i]));
-            Log.v(TAG, String.format("Add metering area for %d, %d, %d",
-                                     startIndex[i], endIndex[i], weight[i]));
-        }
-        mParams.setMeteringAreas(meteringAreas);
-        mTestCamera.setParameters(mParams);
-        takePicture();
-    }
-
-    /**
-     * Runs the metering test when one metering area is defined.
-     *
-     * @param startIndex the index of the grey square where the metering area
-     * starts
-     * @param endIndex the index of the grey square where the metering area
-     * ends.
-     * @param weight the weight for the metering area.
-     */
-    private void runSingleTest(int startIndex, int endIndex, int weight) {
-        mParams = mTestCamera.getParameters();
-        List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
-
-        Log.v(TAG, String.format("Single test for %d, %d, %d", startIndex, endIndex, weight));
-        meteringAreas.add(makeArea(startIndex, endIndex, weight));
-        mParams.setMeteringAreas(meteringAreas);
-        mTestCamera.setParameters(mParams);
-        takePicture();
-    }
-
-    /**
-     * Takes picture with the camera instance linked to this test class.
-     */
-    private void takePicture() {
-        // Waits for the metering to be stable
-        try{
-            Log.v(TAG, "Waiting for metering");
-            Thread.sleep(LONG_SLEEP);
-            Log.v(TAG, "END Waiting");
-        } catch (InterruptedException e) {}
-
-        mTestCamera.takePicture(null, null, null, mTestJpegListener);
-
-        // Locks thread until picture is taken and ready for processing.
-        synchronized (mProcessingImage) {
-            try{
-                Log.v(TAG, "Start waiting for Image");
-
-                mProcessingImage.wait();
-            } catch (InterruptedException e) {
-                Log.v(TAG, "Callback wait fails!");
-            }
-        }
-    }
-
-    /**
-     * Constructs a <code>Camera.Area</code> object of the metering area.
-     * Given the start and end index of one metering area, it takes the upper
-     * left corner of the starting square and the bottom right corner of the
-     * end square to construct an Area.
-     *
-     * @param startIndex the index of the grey square where the metering area
-     * starts
-     * @param endIndex the index of the grey square where the metering area
-     * ends
-     * @param weight the weight of this metering area.
-     *
-     * @return a <code>Camera.Area</code> object which represents this metering
-     * area
-     */
-    private Camera.Area makeArea(int startIndex, int endIndex, int weight) {
-        Rect areaRect = new Rect(mGreyCoordinates[startIndex * 4],
-                                 mGreyCoordinates[startIndex * 4 + 1],
-                                 mGreyCoordinates[endIndex * 4 + 2],
-                                 mGreyCoordinates[endIndex * 4 + 3]);
-        Camera.Area area = new Camera.Area(areaRect, weight);
-
-        return area;
-    }
-
-    @Override
-    public String getDebugText() {
-        return mDebugText;
-    }
-
-    @Override
-    public String getResultText() {
-        return mDebugText;
-    }
-
-    @Override
-    public String getTestName() {
-        return "Metering Test: \n";
-    }
-
-    @Override
-    public String getTestName(int index) {
-        switch (index) {
-            case 0:
-                return "Run all tests";
-            case 1:
-                return "One metering area tests";
-            case 2:
-                return "Multiple metering areas tests";
-            default:
-                return "";
-        }
-    }
-
-    @Override
-    public int getResult(int index) {
-        return mTestResults[index];
-    }
-
-    @Override
-    public int getNumTests() {
-        return mNumTests;
-    }
-
-    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
-        public void onPictureTaken(byte[] data, Camera mCamera) {
-            Log.v(TAG, "Shutter pressed down!");
-            Bitmap inputImage;
-            try {
-                FileOutputStream outStream = new FileOutputStream(
-                    String.format("/sdcard/metering%d.jpg", System.currentTimeMillis()));
-                outStream.write(data);
-                outStream.close();
-            } catch (FileNotFoundException e) {
-            } catch (IOException e) {}
-
-            // Decodes the input data of the camera.
-            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
-
-            // Records the memory address of the native image class instance.
-            long bufferAddress = findNative(inputImage);
-            Log.v(TAG, "findNative method finishes");
-
-            // Cleans up the memory taken by the bitmap.
-            inputImage.recycle();
-            data = null;
-            inputImage = null;
-            System.gc();
-
-            // Add the image data to the native test handler.
-            createMeteringClass(bufferAddress, mTestHandler,
-                                getCheckerCenter(), getCheckerRadius());
-            mCamera.startPreview();
-
-            // Releases thread lock after the image is processed.
-            synchronized (mProcessingImage) {
-                mProcessingImage.notifyAll();
-            }
-        }
-    };
-
-    /**
-     * Finds the coordinates of the grey squares on the color checker.
-     * The coordinates are computed by using the checker center and radius.
-     * The coordinates are converted to a system with (-1000, -1000) in the
-     * upper left corner and (1000, 1000) in the  bottom right corner.
-     *
-     * @param greyCoordinates the array to store the coordinates of the grey
-     * squares
-     * @param checkerCenterAddress the memory address pointing to the vector
-     * storing the color checker's centers.
-     * @param checkerRadiusAddress the memory address pointing to the vetor
-     * storing the color checker's radius.
-     */
-    private native void findGreyCoordinates(int[] greyCoordinates,
-                                            long checkerCenterAddress, long checkerRadiusAddress);
-
-    /**
-     * Creates the native metering test handler with no debug image.
-     *
-     * @return the memory address pointing to the native test handler instance
-     */
-    private native long createMeteringTest();
-
-    /**
-     * Adds the data from the native image class instance to the native test
-     * handler.
-     *
-     * @param bufferAddress the meory address of the native image class
-     * @param handlerAddress the memory address of the native test handler
-     * @param checkerCenterAddress the memory address of the checker cneters
-     * @param checkerRadiusAddress the meory address of the checker radius
-     */
-    private native void createMeteringClass(long bufferAddress, long handlerAddress,
-                                            long checkerCenterAddress,
-                                            long checkerRadiusAddress);
-
-    /**
-     * Process the data stored in the native test handler and stores the
-     * comparison results.
-     *
-     * @param handlerAddress the memory address of the native test handler
-     * @param testCompareResults the boolean array to store the test comparison
-     * results
-     */
-    private native void processMeteringTest(long handlerAddress, boolean[] testCompareResults);
-
-    static {
-        System.loadLibrary("cameraanalyzer");
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/WhiteBalanceTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/WhiteBalanceTest.java
deleted file mode 100644
index a4111eb..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/WhiteBalanceTest.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.camera.analyzer;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.ImageFormat;
-import android.hardware.Camera;
-import android.util.Log;
-import android.widget.ImageView;
-import java.io.FileOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-import java.util.List;
-
-/**
- * Implements a test to verify whether the correlated color temperatures (CTT)
- * of the supported white balance modes are inside the range camera
- * manufacturers generally agree on.
- *
- * The test assumes that the Daylight white balance mode has a CCT of 5200K,
- * which is widely agreed in industry and academics. It then use this as a
- * benchmark and compare images taken with other white balance settings.
- * Using the pixel values of the grey squares on the color checker, the CCT
- * of other white balance modes can be computed. The reference ranges were
- * summarized with the help of online resources. For the Auto mode, the
- * reference CCT is computed as the CCT that will keep the grey squares appear
- * grey in the result image.
- */
-public class WhiteBalanceTest extends CameraTests {
-
-    private static final String TAG = "WhiteBalanceTest";
-
-    /** Current white balance mode. */
-    private String mWhiteBalance;
-    /** Array to store the reference CCT's of each mode. */
-    private int[][] mReferenceTemperature;
-    /** List of supported white balance mode on a device. */
-    private List<String> mWhiteBalanceList;
-    /** The index of the white balance mode "Auto". */
-    private int mAutoId;
-
-    /** Debug results in text. */
-    private String mDebugText;
-    /** Memory address of the native test handler instance. */
-    private long mTestHandler;
-    /** Thread lock. */
-    private final Object mProcessingImage = new Object();
-    /** Test result to show. */
-    private int[] mTestResults;
-    /** Number of test. */
-    private int mNumTests;
-    /** Camera Parameters. */
-    private Camera.Parameters mParams;
-    /** Singleton test instance. */
-    private static WhiteBalanceTest singletonTest = null;
-    /** Boolean to check whehter daylight wb has been recorded. */
-    private boolean mHasDaylight = false;
-
-    /**
-     * Constructs a <code>WhiteBalanceTest</code> instance with a given
-     * Camera pointer.
-     */
-    private WhiteBalanceTest() {
-        super();
-    }
-
-    public void updateCamera() {
-        mAutoId = 0;
-        mHasDaylight = false;
-        mParams = mTestCamera.getParameters();
-        mWhiteBalanceList = mParams.getSupportedWhiteBalance();
-        mNumTests = mWhiteBalanceList.size() + 1;
-        mTestResults = new int[mNumTests];
-        for (int i = 0; i < mNumTests; ++i) {
-            mTestResults[i] = CameraTests.CAMERA_TEST_NOT_RUN;
-        }
-
-        if (mWhiteBalanceList != null) {
-            mReferenceTemperature = new int[mWhiteBalanceList.size()][2];
-
-            // Sets the reference CCT of the supported white balance modes
-            for (int i = 0; i < mWhiteBalanceList.size(); i++) {
-                setReferenceTemperature(i, mWhiteBalanceList.get(i));
-                if (mWhiteBalanceList.get(i).equals("auto")) {
-                    mAutoId = i;
-                }
-            }
-        }
-    }
-
-    public static synchronized WhiteBalanceTest getSingletonTest() {
-        if (singletonTest == null) {
-            Log.v(TAG, "Creating a new WhiteBalanceTest instance");
-            singletonTest = new WhiteBalanceTest();
-            singletonTest.initializeTest();
-        }
-        return singletonTest;
-    }
-
-    private void initializeTest() {
-        mDebugText = new String();
-        // Creates a native white balance test handler.
-        // mTestHandler stores the memory address of this instance.
-        mTestHandler = createWhiteBalanceTest();
-    }
-
-    private void initializeWhiteBalanceTest() {
-        mWhiteBalance = "daylight";
-        takePicture(mWhiteBalance);
-        int colorTemperature = processWhiteBalanceTest(mTestHandler);
-
-        setReferenceTemperature(mAutoId, colorTemperature);
-        mHasDaylight = true;
-    }
-
-    private void takePicture(String whiteBalance) {
-        mParams.setWhiteBalance(whiteBalance);
-        mTestCamera.setParameters(mParams);
-
-        try{
-            Log.v(TAG, "Waiting for white balance to adjust");
-            Thread.sleep(4000);
-            Log.v(TAG, "END Waiting");
-        } catch (InterruptedException e) {}
-
-        mTestCamera.takePicture(null, null, null, mTestJpegListener);
-
-        // Thread locks until image capture is done
-        synchronized (mProcessingImage) {
-            try{
-                Log.v(TAG, "Start waiting for Image");
-                mProcessingImage.wait();
-            } catch (InterruptedException e) {
-                Log.v(TAG, "Callback wait fails!");
-            }
-        }
-    }
-
-    /**
-     * Runs the white balance camera test instance.
-     */
-    @Override
-    public synchronized void run(int index) {
-        Log.v(TAG, "WhiteBalanceTest thread started!");
-
-        if (!mHasDaylight) {
-            initializeWhiteBalanceTest();
-        }
-
-        if (index != 0) {
-            // Retrieves the list of supported white balance mode.
-            mParams = mTestCamera.getParameters();
-
-            int i = index - 1;
-            mWhiteBalance = mWhiteBalanceList.get(i);
-
-            Log.v(TAG, "Current white balance is " + mWhiteBalance);
-
-            takePicture(mWhiteBalance);
-
-            // Processes the white balance test data in the native code.
-            // Returns an array of CCT of each white balance modes, given the CCT
-            // of the "Daylight" mode is 5200K.
-            int colorTemperature = 0;
-
-            Log.v(TAG, "Finished taking picture, ready to process");
-            colorTemperature = processWhiteBalanceTest(mTestHandler);
-
-            // Records the index of the "Auto" white balance mode
-            if (mWhiteBalance.equals("daylight")) {
-                setReferenceTemperature(mAutoId, colorTemperature);
-                prepareDebugText(5200, index);
-                // Computes the reference CCT range of the "Auto" mode. Assuming that
-                // all grey squares on the color checker should be imaged as grey under
-                // a CCT, this CCT is used as a middle point to provide a range.
-                //setReferenceTemperature(mAutoId, colorTemperature[mWhiteBalanceList.size()]);
-            } else {
-                // Prepares the debug output.
-                prepareDebugText(colorTemperature, index);
-            }
-        } else {
-            for (int i = 0; i < mWhiteBalanceList.size(); i++) {
-                run(i + 1);
-            }
-        }
-
-        mParams.setWhiteBalance("auto");
-        mTestCamera.setParameters(mParams);
-    }
-
-    /**
-     * Prepares the debug results in HTML text. For each white balance mode,
-     * the CCT will be printed in green if it is in the reference range and
-     * red otherwise. The reference CCT range is also printed below, with
-     * green meaning the CCT range is satisfied and red otherwise.
-     *
-     * @param colorTemperature the CCT of the supported white balance modes
-     */
-    private void prepareDebugText(int colorTemperature, int index) {
-        mDebugText += String.format("CCT Ref is %d, %d, and CCT is %d",
-                                  mReferenceTemperature[index - 1][0],
-                                  mReferenceTemperature[index - 1][1],
-                                  colorTemperature);
-        Log.v(TAG, String.format("CCT Ref is %d, %d, and CCT is %d",
-                                  mReferenceTemperature[index - 1][0],
-                                  mReferenceTemperature[index - 1][1],
-                                  colorTemperature));
-        if ((colorTemperature >= mReferenceTemperature[index - 1][0]) &&
-                (colorTemperature <= mReferenceTemperature[index - 1][1])) {
-            mTestResults[index] = CameraTests.CAMERA_TEST_SUCCESS;
-        } else {
-            mTestResults[index] = CameraTests.CAMERA_TEST_FAILURE;
-        }
-
-    }
-
-    @Override
-    public String getDebugText() {
-        return mDebugText;
-    }
-
-    @Override
-    public String getResultText() {
-        return mDebugText;
-    }
-
-    @Override
-    public String getTestName() {
-        return "White Balance Test: \n";
-    }
-
-    @Override
-    public String getTestName(int index) {
-        if (index != 0){
-            return String.format("%s mode test", mWhiteBalanceList.get(index - 1));
-        } else {
-            return "Run all tests";
-        }
-    }
-
-    @Override
-    public int getResult(int index) {
-        return mTestResults[index];
-    }
-
-    @Override
-    public int getNumTests() {
-        return mNumTests;
-    }
-
-    /**
-     * Sets the reference temperatures for the white balance modes of
-     * incandescent, fluorescent, warm-fluorescent, daylight, cloudy, shade
-     * and twilight. These are the currently supported White balance mode
-     * listed on the Android camera API.
-     *
-     * The reference range are summarized based on the published settings of
-     * Canon, Nikon and the references from Wikipedia on color temperature.
-     *
-     * @param i the index of the current white balance mode
-     * @param referenceWhiteBalance the name of the white balance mode.
-     */
-    private void setReferenceTemperature(int i, String referenceWhiteBalance) {
-        if (referenceWhiteBalance.equals("incandescent")) {
-            mReferenceTemperature[i][0] = 2500;
-            mReferenceTemperature[i][1] = 3500;
-        } else if (referenceWhiteBalance.equals("fluorescent")) {
-            mReferenceTemperature[i][0] = 3000;
-            mReferenceTemperature[i][1] = 6500;
-        } else if (referenceWhiteBalance.equals("warm-fluorescent")) {
-            mReferenceTemperature[i][0] = 2500;
-            mReferenceTemperature[i][1] = 3000;
-        } else if (referenceWhiteBalance.equals("daylight")) {
-            mReferenceTemperature[i][0] = 5000;
-            mReferenceTemperature[i][1] = 5400;
-        } else if (referenceWhiteBalance.equals("cloudy-daylight")) {
-            mReferenceTemperature[i][0] = 5500;
-            mReferenceTemperature[i][1] = 7500;
-        } else if (referenceWhiteBalance.equals("shade")) {
-            mReferenceTemperature[i][0] = 6800;
-            mReferenceTemperature[i][1] = 8000;
-        } else if (referenceWhiteBalance.equals("twilight")) {
-            mReferenceTemperature[i][0] = 10000;
-            mReferenceTemperature[i][1] = 14000;
-        }
-    }
-
-    /** Sets a reference range of CCT based on a given middle point CCT.
-     * The rerence range is from -10% of the CCT value to +10%.
-     *
-     * @param i the index of the current white balance mode
-     * @param t the middle point CCT.
-     */
-    private void setReferenceTemperature(int i, int t) {
-        mReferenceTemperature[i][0] = (int)((double)t * 0.9);
-        mReferenceTemperature[i][1] = (int)((double)t * 1.1);
-    }
-
-    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
-        public void onPictureTaken(byte[] data, Camera mCamera) {
-            Log.v(TAG, "Shutter pressed down!");
-            Bitmap inputImage;
-            try {
-                FileOutputStream outStream = new FileOutputStream(
-                        String.format("/sdcard/wb%d.jpg", System.currentTimeMillis()));
-                outStream.write(data);
-                outStream.close();
-            } catch (FileNotFoundException e) {
-            } catch (IOException e) {}
-            // Decodes the camera data to Bitmap and creates a native image
-            // class with the Bitmap.
-            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
-            long bufferAddress = findNative(inputImage);
-            Log.v(TAG, "findNative method finishes");
-
-            // Cleans up the Bitmap memory space.
-            inputImage.recycle();
-            data = null;
-            inputImage = null;
-            System.gc();
-
-            // Adds the data from the current image base class to the native
-            // white balance test handler.
-            createWhiteBalanceClass(bufferAddress, mTestHandler,
-                                    getCheckerCenter(), getCheckerRadius(), mWhiteBalance);
-
-            mCamera.startPreview();
-
-            // Notifies the thread lock that the image capture is finished
-            synchronized (mProcessingImage) {
-                mProcessingImage.notifyAll();
-            }
-        }
-    };
-
-    /**
-     * Creates a native white balance test handler.
-     *
-     * @return the memory address of the test handler
-     */
-    private native long createWhiteBalanceTest();
-
-    /**
-     * Adds the data of interest from the image class pointed by
-     * <code>bufferAddress</code> to the handler class pointed by
-     * <code>handlerAddress</code> by using the color checker coordinates.
-     * Also sets the white balance of this test.
-     *
-     * @param bufferAddress the memory address of the native image class
-     * containing the current camera captured image
-     * @param handlerAddress the memory address of the native white balance
-     * test handler instance
-     * @param checkerCenterAddress the memory address of the color checker
-     * center coordinates
-     * @param checkerRadiusAddress the memory address of the color checker
-     * radius
-     * @param whiteBalance the white balance mode used for shooting the image
-     */
-    private native void createWhiteBalanceClass(long bufferAddress, long handlerAddress,
-                                                long checkerCenterAddress,
-                                                long checkerRadiusAddress,
-                                                String whiteBalance);
-
-    /**
-     * Processes the white balance test in the native code. This is executed
-     * after the images are taken with all possible white balance modes. It
-     * uses the "Daylight" white balance mode as reference and computes the
-     * CCT of other white balance modes.
-     *
-     * @param handlerAddress the memory address of the native white balance
-     * test handler instance.
-     * @param colorTemperature the array to store the computed CCT of all white
-     * balance modes.
-     */
-    private native int processWhiteBalanceTest(long handlerAddress);
-
-    private native int getAutoTemperature(long handlerAddress);
-
-    static {
-        System.loadLibrary("cameraanalyzer");
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index c1cc1f9..628ff3e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -58,7 +58,8 @@
 public class ByodFlowTestActivity extends PassFailButtons.ListActivity {
 
     private final String TAG = "ByodFlowTestActivity";
-    private static final int REQUEST_STATUS = 1;
+    private static final int REQUEST_PROFILE_OWNER_STATUS = 1;
+    private static final int REQUEST_INTENT_FILTERS_STATUS = 2;
 
     private ComponentName mAdminReceiverComponent;
 
@@ -80,6 +81,7 @@
     private TestItem mLocationSettingsVisibleTest;
     private TestItem mCredSettingsVisibleTest;
     private TestItem mPrintSettingsVisibleTest;
+    private TestItem mIntentFiltersTest;
 
     private int mCurrentTestPosition;
 
@@ -137,10 +139,13 @@
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        // Called after queryProfileOwner()
         super.onActivityResult(requestCode, resultCode, data);
-        if (requestCode == REQUEST_STATUS && resultCode == RESULT_OK) {
+        // Called after queryProfileOwner()
+        if (requestCode == REQUEST_PROFILE_OWNER_STATUS && resultCode == RESULT_OK) {
             handleStatusUpdate(data);
+            // Called after checkIntentFilters()
+        } else if (requestCode == REQUEST_INTENT_FILTERS_STATUS) {
+            handleIntentFiltersStatus(resultCode);
         }
     }
 
@@ -224,6 +229,15 @@
                 R.string.provisioning_byod_cross_profile_instruction,
                 chooser);
 
+        // Test for checking if the required intent filters are set during managed provisioning.
+        mIntentFiltersTest = new TestItem(this,
+                R.string.provisioning_byod_cross_profile_intent_filters) {
+            @Override
+            public void performTest(ByodFlowTestActivity activity) {
+                checkIntentFilters();
+            }
+        };
+
         mTests.add(mProfileOwnerInstalled);
 
         // Badge related tests
@@ -241,6 +255,7 @@
         mTests.add(mCrossProfileIntentFiltersTest);
         mTests.add(mDisableNonMarketTest);
         mTests.add(mEnableNonMarketTest);
+        mTests.add(mIntentFiltersTest);
     }
 
     @Override
@@ -321,9 +336,8 @@
 
     private void startByodProvisioning() {
         Intent sending = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
-        sending.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
-                mAdminReceiverComponent.getPackageName());
-        sending.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminReceiverComponent);
+        sending.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
+                mAdminReceiverComponent);
 
         if (sending.resolveActivity(getPackageManager()) != null) {
             // ManagedProvisioning must be started with startActivityForResult, but we don't
@@ -337,7 +351,7 @@
     private void queryProfileOwner(boolean showToast) {
         try {
             Intent intent = new Intent(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
-            startActivityForResult(intent, REQUEST_STATUS);
+            startActivityForResult(intent, REQUEST_PROFILE_OWNER_STATUS);
         }
         catch (ActivityNotFoundException e) {
             Log.d(TAG, "queryProfileOwner: ActivityNotFoundException", e);
@@ -359,6 +373,35 @@
         }
     }
 
+    private void checkIntentFilters() {
+        try {
+            // We disable the ByodHelperActivity in the primary profile. So, this intent
+            // will be handled by the ByodHelperActivity in the managed profile.
+            Intent intent = new Intent(ByodHelperActivity.ACTION_CHECK_INTENT_FILTERS);
+            startActivityForResult(intent, REQUEST_INTENT_FILTERS_STATUS);
+        } catch (ActivityNotFoundException e) {
+            Log.d(TAG, "checkIntentFilters: ActivityNotFoundException", e);
+            setTestResult(mIntentFiltersTest, TestResult.Failed);
+            showToast(R.string.provisioning_byod_no_activity);
+        }
+    }
+
+    private void handleIntentFiltersStatus(int resultCode) {
+        // we use the resultCode from ByodHelperActivity in the managed profile to know if certain
+        // intents fired from the managed profile are forwarded.
+        final boolean intentFiltersSetForManagedIntents = (resultCode == RESULT_OK);
+        // Since the ByodFlowTestActivity is running in the primary profile, we directly use
+        // the IntentFiltersTestHelper to know if certain intents fired from the primary profile
+        // are forwarded.
+        final boolean intentFiltersSetForPrimaryIntents =
+                new IntentFiltersTestHelper(this).checkCrossProfileIntentFilters(
+                        IntentFiltersTestHelper.FLAG_INTENTS_FROM_PRIMARY);
+        final boolean intentFiltersSet =
+                intentFiltersSetForPrimaryIntents & intentFiltersSetForManagedIntents;
+        setTestResult(mIntentFiltersTest,
+                intentFiltersSet ? TestResult.Passed : TestResult.Failed);
+    }
+
     private void disableComponent() {
         // Disable app components in the current profile, so only the counterpart in the other profile
         // can respond (via cross-profile intent filter)
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 277324c..13af890 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -61,6 +61,12 @@
     public static final String ACTION_INSTALL_APK = "com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK";
     public static final String EXTRA_ALLOW_NON_MARKET_APPS = INSTALL_NON_MARKET_APPS;
 
+    // Primary -> managed intent: check if the required cross profile intent filters are set.
+    public static final String ACTION_CHECK_INTENT_FILTERS =
+            "com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS";
+
+    public static final int RESULT_FAILED = RESULT_FIRST_USER;
+
     private static final int REQUEST_INSTALL_PACKAGE = 1;
 
     private static final String ORIGINAL_SETTINGS_NAME = "original settings";
@@ -120,6 +126,12 @@
 
             // Not yet ready to finish- wait until the result comes back
             return;
+            // Queried by CtsVerifier in the primary side using startActivityForResult.
+        } else if (action.equals(ACTION_CHECK_INTENT_FILTERS)) {
+            final boolean intentFiltersSetForManagedIntents =
+                    new IntentFiltersTestHelper(this).checkCrossProfileIntentFilters(
+                            IntentFiltersTestHelper.FLAG_INTENTS_FROM_MANAGED);
+            setResult(intentFiltersSetForManagedIntents? RESULT_OK : RESULT_FAILED, null);
         }
         // This activity has no UI and is only used to respond to CtsVerifier in the primary side.
         finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index fa7bc4c..58c068f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -49,6 +49,7 @@
             filter.addAction(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
             filter.addAction(ByodHelperActivity.ACTION_REMOVE_PROFILE_OWNER);
             filter.addAction(ByodHelperActivity.ACTION_INSTALL_APK);
+            filter.addAction(ByodHelperActivity.ACTION_CHECK_INTENT_FILTERS);
             filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
             filter.addAction(WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
new file mode 100644
index 0000000..579cbcc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.media.audiofx.AudioEffect;
+import android.net.Uri;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.AlarmClock;
+import android.provider.CalendarContract.Events;
+import android.provider.MediaStore;
+import android.provider.Settings;
+import android.speech.RecognizerIntent;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for testing if the required cross profile intent filters are set during the
+ * managed provisioning.
+ */
+public class IntentFiltersTestHelper {
+
+    private static final String TAG = "IntentFiltersTestHelper";
+
+    // These are the intents which can be forwarded to the managed profile.
+    private static final Intent[] forwardedIntentsFromPrimary = new Intent[] {
+        new Intent(Intent.ACTION_SEND).setType("*/*"),
+        new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*")
+    };
+
+    // These are the intents which can be forwarded to the primary profile.
+    private static final Intent[] forwardedIntentsFromManaged = new Intent[] {
+        new Intent(AlarmClock.ACTION_SET_ALARM),
+        new Intent(AlarmClock.ACTION_SET_TIMER),
+        new Intent(AlarmClock.ACTION_SHOW_ALARMS),
+        new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
+        new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
+        new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA),
+        new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA),
+        new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE),
+        new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
+        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")),
+        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")),
+        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")),
+        new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("sms:07700900100?body=Hello%20world")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("mms:07700900100?body=Hello%20world")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
+        new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS),
+        new Intent(Settings.ACTION_APN_SETTINGS),
+        new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS),
+        new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
+        new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS),
+        new Intent(Settings.ACTION_DATE_SETTINGS),
+        new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
+        new Intent(Settings.ACTION_DISPLAY_SETTINGS),
+        new Intent(Settings.ACTION_DREAM_SETTINGS),
+        new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
+        new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS),
+        new Intent(Settings.ACTION_LOCALE_SETTINGS),
+        new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS),
+        new Intent(Settings.ACTION_NFC_SETTINGS),
+        new Intent(Settings.ACTION_NFCSHARING_SETTINGS),
+        new Intent(Settings.ACTION_PRIVACY_SETTINGS),
+        new Intent(Settings.ACTION_SETTINGS),
+        new Intent(Settings.ACTION_SOUND_SETTINGS),
+        new Intent(Settings.ACTION_WIRELESS_SETTINGS),
+        new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
+        new Intent("android.net.vpn.SETTINGS"),
+        new Intent(CardEmulation.ACTION_CHANGE_DEFAULT),
+        new Intent("android.settings.ACCOUNT_SYNC_SETTINGS"),
+        new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
+        new Intent(Settings.ACTION_HOME_SETTINGS),
+        new Intent("android.settings.LICENSE"),
+        new Intent("android.settings.NOTIFICATION_SETTINGS"),
+        new Intent(Settings.ACTION_SHOW_REGULATORY_INFO),
+        new Intent("android.settings.USER_SETTINGS"),
+        new Intent("android.settings.ZEN_MODE_SETTINGS"),
+        new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"),
+        new Intent("com.android.settings.STORAGE_USB_SETTINGS"),
+        new Intent("com.android.settings.TTS_SETTINGS"),
+        new Intent("com.android.settings.USER_DICTIONARY_EDIT"),
+        new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")),
+        new Intent("android.intent.action.CALL_EMERGENCY").setData(Uri.parse("tel:123")),
+        new Intent("android.intent.action.CALL_PRIVILEGED").setData(Uri.parse("tel:123")),
+        new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
+        new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS),
+        new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS),
+        new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS),
+        new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
+        new Intent(Settings.ACTION_SYNC_SETTINGS),
+        new Intent(Settings.ACTION_ADD_ACCOUNT),
+        new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory(
+                Intent.CATEGORY_OPENABLE),
+        new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory(
+                Intent.CATEGORY_OPENABLE),
+        new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
+    };
+
+    // These are the intents which cannot be forwarded to the primary profile.
+    private static final Intent[] notForwardedIntentsFromManaged = new Intent[] {
+        new Intent(Intent.ACTION_INSERT).setData(
+                Uri.parse("content://browser/bookmarks")),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("http://www.example.com")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Intent.ACTION_SENDTO).setData(
+                Uri.parse("mailto:user@example.com")),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("mailto:user@example.com")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("geo:0,0?q=BuckinghamPalace")),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("http://example.com/oceans.mp4")).setType("video/mp4"),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("http://www.example.com/horse.mp3")).setType("audio/*"),
+        new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH),
+        new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION),
+        new Intent(Intent.ACTION_VIEW).setData(
+                Uri.parse("market://details?id=com.android.chrome")).addCategory(
+                Intent.CATEGORY_BROWSABLE),
+        new Intent(Intent.ACTION_WEB_SEARCH),
+        new Intent(Settings.ACTION_SEARCH_SETTINGS),
+        new Intent(Settings.ACTION_PRINT_SETTINGS),
+        new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE),
+        new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS),
+        new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS),
+        new Intent(Settings.ACTION_APPLICATION_SETTINGS),
+        new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
+                Uri.parse("package:com.android.chrome")),
+        new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS"),
+        new Intent(Settings.ACTION_WIFI_IP_SETTINGS),
+        new Intent(Settings.ACTION_WIFI_SETTINGS),
+        new Intent("android.settings.SHOW_INPUT_METHOD_PICKER"),
+        new Intent(Intent.ACTION_INSERT).setData(Events.CONTENT_URI),
+        new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)
+    };
+
+    // This flag specifies we are dealing with intents fired from the primary profile.
+    public static final int FLAG_INTENTS_FROM_PRIMARY = 1;
+    // This flag specifies we are dealing with intents fired from the managed profile.
+    public static final int FLAG_INTENTS_FROM_MANAGED = 2;
+
+    private Context mContext;
+
+    IntentFiltersTestHelper(Context context) {
+        mContext = context;
+    }
+
+    public boolean checkCrossProfileIntentFilters(int flag) {
+        boolean crossProfileIntentFiltersSet;
+        if (flag == FLAG_INTENTS_FROM_PRIMARY) {
+            crossProfileIntentFiltersSet = checkForIntentsFromPrimary();
+        } else {
+            crossProfileIntentFiltersSet = checkForIntentsFromManaged();
+        }
+        return crossProfileIntentFiltersSet;
+    }
+
+    /**
+     * Checks if required cross profile intent filters are set for the intents fired from the
+     * primary profile.
+     */
+    private boolean checkForIntentsFromPrimary() {
+        // Get the class name of the intentForwarderActivity in the primary profile by firing an
+        // intent which we know will be forwarded from primary profile to managed profile.
+        ActivityInfo forwarderActivityInfo =
+                getForwarderActivityInfo(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
+        if (forwarderActivityInfo == null) {
+            return false;
+        }
+
+        // Check for intents which can be forwarded to the managed profile.
+        Intent intent = checkForIntentsNotHandled(forwardedIntentsFromPrimary,
+                forwarderActivityInfo, true);
+        if (intent != null) {
+            Log.d(TAG, intent + " from primary profile should be forwarded to the " +
+                    "managed profile but is not.");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Checks if required cross profile intent filters are set for the intents fired from the
+     * managed profile.
+     */
+    private boolean checkForIntentsFromManaged() {
+        // Get the class name of the intentForwarderActivity in the managed profile by firing an
+        // intent which we know will be forwarded from managed profile to primary profile.
+        ActivityInfo forwarderActivityInfo =
+                getForwarderActivityInfo(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
+        if (forwarderActivityInfo == null) {
+            return false;
+        }
+
+        // Check for intents which can be forwarded to the primary profile.
+        Intent intent = checkForIntentsNotHandled(forwardedIntentsFromManaged,
+                forwarderActivityInfo, true);
+        if (intent != null) {
+            Log.d(TAG, intent + " from managed profile should be forwarded to the " +
+                    "primary profile but is not.");
+            return false;
+        }
+
+        // Check for intents which cannot be forwarded to the primary profile.
+        intent = checkForIntentsNotHandled(notForwardedIntentsFromManaged,
+                forwarderActivityInfo, false);
+        if (intent != null) {
+            Log.d(TAG, intent + " from managed profile should not be forwarded to the " +
+                    "primary profile but it is.");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Checks if the intentForwarderActivity can handle the intent passed.
+     */
+    private boolean canForwarderActivityHandleIntent(Intent intent,
+            ActivityInfo forwarderActivityInfo) {
+        // Get all the activities which can handle the intent.
+        List<ResolveInfo> resolveInfoList =
+                mContext.getPackageManager().queryIntentActivities(intent,
+                        PackageManager.MATCH_DEFAULT_ONLY);
+        // Check if intentForwarderActivity is part of the list.
+        for (ResolveInfo resolveInfo : resolveInfoList) {
+            if (forwarderActivityInfo.packageName.equals(resolveInfo.activityInfo.packageName)
+                    && forwarderActivityInfo.name.equals(resolveInfo.activityInfo.name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the class name of the intentForwarderActivity.
+     */
+    private ActivityInfo getForwarderActivityInfo(String action) {
+        Intent intent = new Intent(action);
+        List<ResolveInfo> resolveInfoList =
+                mContext.getPackageManager().queryIntentActivities(intent,
+                        PackageManager.MATCH_DEFAULT_ONLY);
+        if (resolveInfoList.isEmpty() || resolveInfoList.size() > 1) {
+            Log.d(TAG, "There should be exactly one activity IntentForwarder which " +
+                    "handles the intent " + intent);
+            return null;
+        }
+        return resolveInfoList.get(0).activityInfo;
+    }
+
+    /**
+     * Checks if the intents passed are correctly handled.
+     * @return {@code null} if all the intents are correctly handled
+     *         otherwise, the first intent in the list which is not handled correctly.
+     */
+    private Intent checkForIntentsNotHandled(Intent[] intentList,
+            ActivityInfo expectedForwarderActivityInfo, boolean canResolve) {
+        for (Intent intent : intentList) {
+            if (canForwarderActivityHandleIntent(intent,
+                    expectedForwarderActivityInfo) != canResolve) {
+                return intent;
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/build/config.mk b/build/config.mk
index a836f92..ffc71ba 100644
--- a/build/config.mk
+++ b/build/config.mk
@@ -14,7 +14,7 @@
 
 # Test XMLs, native executables, and packages will be placed in this
 # directory before creating the final CTS distribution.
-CTS_TESTCASES_OUT := $(HOST_OUT)/cts-testcases
+CTS_TESTCASES_OUT := $(HOST_OUT)/cts/android-cts/repository/testcases
 
 # Scanners of source files for tests which are then inputed into
 # the XML generator to produce test XMLs.
@@ -34,6 +34,9 @@
 # Holds the target architecture to build for.
 CTS_TARGET_ARCH := $(TARGET_ARCH)
 
+# default module config filename
+CTS_MODULE_TEST_CONFIG := AndroidTest.xml
+
 # CTS build rules
 BUILD_CTS_EXECUTABLE := cts/build/test_executable.mk
 BUILD_CTS_PACKAGE := cts/build/test_package.mk
@@ -42,3 +45,5 @@
 BUILD_CTS_TARGET_JAVA_LIBRARY := cts/build/test_target_java_library.mk
 BUILD_CTS_UI_JAVA_LIBRARY := cts/build/test_uiautomator.mk
 BUILD_CTS_DEQP_PACKAGE := cts/build/test_deqp_package.mk
+BUILD_CTS_SUPPORT_PACKAGE := cts/build/support_package.mk
+BUILD_CTS_MODULE_TEST_CONFIG := cts/build/module_test_config.mk
diff --git a/apps/CtsVerifier/lib/Android.mk b/build/module_test_config.mk
similarity index 61%
rename from apps/CtsVerifier/lib/Android.mk
rename to build/module_test_config.mk
index 56a3fa8..1a397ac 100644
--- a/apps/CtsVerifier/lib/Android.mk
+++ b/build/module_test_config.mk
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 2011 The Android Open Source Project
+# Copyright (C) 2015 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,6 +11,11 @@
 # 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.
-#
 
-include $(call all-subdir-makefiles)
+cts_module_test_config := $(if $(wildcard \
+	$(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG)), \
+	$(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).config)
+ifneq ($(cts_module_test_config),)
+$(cts_module_test_config): $(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG) | $(ACP)
+	$(call copy-file-to-target)
+endif
diff --git a/build/support_package.mk b/build/support_package.mk
new file mode 100644
index 0000000..16a254e
--- /dev/null
+++ b/build/support_package.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Builds a package which is needed by a test package and copies it to CTS
+#
+# Replace "include $(BUILD_PACKAGE)" with "include $(BUILD_CTS_SUPPORT_PACKAGE)"
+#
+
+# Disable by default so "m cts" will work in emulator builds
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+cts_support_apks :=
+$(foreach fp, $(ALL_MODULES.$(LOCAL_PACKAGE_NAME).BUILT_INSTALLED),\
+  $(eval pair := $(subst :,$(space),$(fp)))\
+  $(eval built := $(word 1,$(pair)))\
+  $(eval installed := $(CTS_TESTCASES_OUT)/$(notdir $(word 2,$(pair))))\
+  $(eval $(call copy-one-file, $(built), $(installed)))\
+  $(eval cts_support_apks += $(installed)))
+
+# Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
+$(my_register_name) : $(cts_support_apks)
diff --git a/build/test_deqp_package.mk b/build/test_deqp_package.mk
index b07876d..e4b8281 100644
--- a/build/test_deqp_package.mk
+++ b/build/test_deqp_package.mk
@@ -19,12 +19,11 @@
 CTS_DEQP_CONFIG_PATH := $(call my-dir)
 
 cts_library_xml := $(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(DEQP_API).xml
-
 $(cts_library_xml): MUSTPASS_XML_FILE := external/deqp/android/cts/com.drawelements.deqp.$(DEQP_API).xml
 $(cts_library_xml): PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
 $(cts_library_xml): PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
 $(cts_library_xml): PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
-$(cts_library_xml): $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/package.apk external/deqp/android/cts/com.drawelements.deqp.$(DEQP_API).xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
+$(cts_library_xml): external/deqp/android/cts/com.drawelements.deqp.$(DEQP_API).xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for $(PRIVATE_TEST_NAME)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	
@@ -39,6 +38,6 @@
 										| grep --only-matching -e " abis=\"[^\"]*\""))
 	
 # Patch xml caselist with supported abi
-	$(hide) $(SED_EXTENDED) -e 's:^<Test (.*)/>$$:<Test \1 $(supported_abi_attr) />:' \
+	$(hide) $(SED_EXTENDED) -e 's:^<Test ((.[^/]|[^/])*)(/?)>$$:<Test \1 $(supported_abi_attr) \3>:' \
 				< $(MUSTPASS_XML_FILE) \
 				> $@
diff --git a/build/test_executable.mk b/build/test_executable.mk
index 3cabdf3..3a2cb8e 100644
--- a/build/test_executable.mk
+++ b/build/test_executable.mk
@@ -26,13 +26,19 @@
 LOCAL_CXX_STL := libc++
 include $(BUILD_EXECUTABLE)
 
-cts_executable_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
+cts_executable_bin :=
+$(foreach fp, $(ALL_MODULES.$(LOCAL_MODULE).BUILT) $(ALL_MODULES.$(LOCAL_MODULE)$(TARGET_2ND_ARCH_MODULE_SUFFIX).BUILT),\
+  $(eval installed := $(CTS_TESTCASES_OUT)/$(notdir $(fp)))\
+  $(eval $(call copy-one-file, $(fp), $(installed)))\
+  $(eval cts_executable_bin += $(installed)))
 
+cts_executable_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
 $(cts_executable_xml): PRIVATE_TEST_PACKAGE := $(LOCAL_CTS_TEST_PACKAGE)
 $(cts_executable_xml): PRIVATE_EXECUTABLE := $(LOCAL_MODULE)
 $(cts_executable_xml): PRIVATE_LIST_EXECUTABLE := $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)_list
 $(cts_executable_xml): $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)_list
-$(cts_executable_xml): $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES)) $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_NATIVE_TEST_SCANNER) $(CTS_XML_GENERATOR) $(cts_list_executable)
+$(cts_executable_xml): $(cts_executable_bin)
+$(cts_executable_xml): $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES)) $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_NATIVE_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for native package $(PRIVATE_TEST_PACKAGE)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(hide) $(PRIVATE_LIST_EXECUTABLE) --gtest_list_tests | \
@@ -46,4 +52,4 @@
 						-o $@
 
 # Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
-$(my_register_name) : $(cts_executable_xml)
+$(my_register_name) : $(cts_executable_bin) $(cts_executable_xml)
diff --git a/build/test_gtest_package.mk b/build/test_gtest_package.mk
index dd1269b..fc468d0 100644
--- a/build/test_gtest_package.mk
+++ b/build/test_gtest_package.mk
@@ -23,23 +23,17 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
-cts_package_apk := $(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).apk
 cts_package_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).xml
-cts_test_list := $(LOCAL_PATH)/$(LOCAL_MODULE)_list.txt
-
-$(cts_package_apk): PRIVATE_PACKAGE := $(LOCAL_PACKAGE_NAME)
-$(cts_package_apk): $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/package.apk | $(ACP)
-	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
-	$(hide) $(ACP) -fp $(call intermediates-dir-for,APPS,$(PRIVATE_PACKAGE))/package.apk $@
-
 $(cts_package_xml): PRIVATE_PATH := $(LOCAL_PATH)
 $(cts_package_xml): PRIVATE_TEST_PACKAGE := android.$(notdir $(LOCAL_PATH))
 $(cts_package_xml): PRIVATE_EXECUTABLE := $(LOCAL_MODULE)
 $(cts_package_xml): PRIVATE_MANIFEST := $(LOCAL_PATH)/AndroidManifest.xml
-$(cts_package_xml): PRIVATE_TEST_LIST := $(cts_test_list)
-$(cts_package_xml): $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES))  $(CTS_NATIVE_TEST_SCANNER) $(CTS_XML_GENERATOR) $(cts_test_list)
+$(cts_package_xml): PRIVATE_TEST_LIST := $(LOCAL_PATH)/$(LOCAL_MODULE)_list.txt
+$(cts_package_xml): $(LOCAL_PATH)/$(LOCAL_MODULE)_list.txt
+$(cts_package_xml): $(cts_support_apks)
+$(cts_package_xml): $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES))  $(CTS_NATIVE_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for wrapped native package $(PRIVATE_EXECUTABLE)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(hide) cat $(PRIVATE_TEST_LIST) | \
@@ -54,4 +48,4 @@
 						-o $@
 
 # Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
-$(my_register_name) : $(cts_package_apk) $(cts_package_xml)
+$(my_register_name) : $(cts_package_xml)
diff --git a/build/test_host_java_library.mk b/build/test_host_java_library.mk
index 8ed5670..7e86ac9 100644
--- a/build/test_host_java_library.mk
+++ b/build/test_host_java_library.mk
@@ -19,17 +19,21 @@
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
-cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
+cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+	$(copy-file-to-target)
 
 cts_src_dirs := $(LOCAL_PATH)/src
 cts_src_dirs += $(sort $(dir $(LOCAL_GENERATED_SOURCES)))
 cts_src_dirs := $(addprefix -s , $(cts_src_dirs))
 
+cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
 $(cts_library_xml): PRIVATE_SRC_DIRS := $(cts_src_dirs)
 $(cts_library_xml): PRIVATE_TEST_PACKAGE := $(LOCAL_CTS_TEST_PACKAGE)
 $(cts_library_xml): PRIVATE_LIBRARY := $(LOCAL_MODULE)
 $(cts_library_xml): PRIVATE_JAR_PATH := $(LOCAL_MODULE).jar
-$(cts_library_xml): $(HOST_OUT_JAVA_LIBRARIES)/$(LOCAL_MODULE).jar $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
+$(cts_library_xml): $(cts_library_jar)
+$(cts_library_xml): $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for host library $(PRIVATE_LIBRARY)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(hide) $(CTS_JAVA_TEST_SCANNER) $(PRIVATE_SRC_DIRS) \
@@ -44,4 +48,4 @@
 						-o $@
 
 # Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
-$(my_register_name) : $(cts_library_xml)
+$(my_register_name) : $(cts_library_jar) $(cts_library_xml)
diff --git a/build/test_package.mk b/build/test_package.mk
index 7589787..c6b0865 100644
--- a/build/test_package.mk
+++ b/build/test_package.mk
@@ -23,20 +23,14 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 
-include $(BUILD_PACKAGE)
-
-cts_package_apk := $(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).apk
-cts_package_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).xml
+include $(BUILD_CTS_SUPPORT_PACKAGE)
+include $(BUILD_CTS_MODULE_TEST_CONFIG)
 
 cts_src_dirs := $(LOCAL_PATH)
 cts_src_dirs += $(sort $(dir $(LOCAL_GENERATED_SOURCES)))
 cts_src_dirs := $(addprefix -s , $(cts_src_dirs))
 
-$(cts_package_apk): PRIVATE_PACKAGE := $(LOCAL_PACKAGE_NAME)
-$(cts_package_apk): $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/package.apk | $(ACP)
-	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
-	$(hide) $(ACP) -fp $(call intermediates-dir-for,APPS,$(PRIVATE_PACKAGE))/package.apk $@
-
+cts_package_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).xml
 $(cts_package_xml): PRIVATE_SRC_DIRS := $(cts_src_dirs)
 $(cts_package_xml): PRIVATE_INSTRUMENTATION := $(LOCAL_INSTRUMENTATION_FOR)
 $(cts_package_xml): PRIVATE_PACKAGE := $(LOCAL_PACKAGE_NAME)
@@ -48,7 +42,9 @@
 $(cts_package_xml): PRIVATE_TEST_PACKAGE := $(PRIVATE_CTS_TEST_PACKAGE_NAME_)
 $(cts_package_xml): PRIVATE_MANIFEST := $(LOCAL_PATH)/AndroidManifest.xml
 $(cts_package_xml): PRIVATE_TEST_TYPE := $(if $(LOCAL_CTS_TEST_RUNNER),$(LOCAL_CTS_TEST_RUNNER),'')
-$(cts_package_xml): $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/package.apk $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
+$(cts_package_xml): $(cts_support_apks)
+$(cts_package_xml): $(cts_module_test_config)
+$(cts_package_xml): $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for java package $(PRIVATE_PACKAGE)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(hide) $(CTS_JAVA_TEST_SCANNER) \
@@ -64,6 +60,5 @@
 						-b $(CTS_UNSUPPORTED_ABIS) \
 						-a $(CTS_TARGET_ARCH) \
 						-o $@
-
 # Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
-$(my_register_name) : $(cts_package_apk) $(cts_package_xml)
+$(my_register_name) : $(cts_package_xml) $(cts_module_test_config)
diff --git a/build/test_target_java_library.mk b/build/test_target_java_library.mk
index 04fffb9..2d3abfb 100644
--- a/build/test_target_java_library.mk
+++ b/build/test_target_java_library.mk
@@ -19,8 +19,9 @@
 # Disable by default so "m cts" will work in emulator builds
 LOCAL_DEX_PREOPT := false
 include $(BUILD_JAVA_LIBRARY)
+
 cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
-$(cts_library_jar): $(LOCAL_BUILT_MODULE) | $(ACP)
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
 	$(copy-file-to-target)
 
 cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
@@ -30,7 +31,8 @@
 $(cts_library_xml): PRIVATE_LIBRARY := $(LOCAL_MODULE)
 $(cts_library_xml): PRIVATE_JAR_PATH := $(LOCAL_MODULE).jar
 $(cts_library_xml): PRIVATE_RUNTIME_ARGS := $(LOCAL_CTS_TARGET_RUNTIME_ARGS)
-$(cts_library_xml): $(TARGET_OUT_JAVA_LIBRARIES)/$(LOCAL_MODULE).jar $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
+$(cts_library_xml): $(cts_library_jar)
+$(cts_library_xml): $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for target library $(PRIVATE_LIBRARY)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(hide) $(CTS_JAVA_TEST_SCANNER) -s $(PRIVATE_PATH) \
diff --git a/build/test_uiautomator.mk b/build/test_uiautomator.mk
index cad6e4f..b573d25 100644
--- a/build/test_uiautomator.mk
+++ b/build/test_uiautomator.mk
@@ -21,25 +21,23 @@
 
 include $(BUILD_JAVA_LIBRARY)
 
-cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml 
 cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+	$(call copy-file-to-target)
 
 cts_src_dirs := $(LOCAL_PATH)/src
 cts_src_dirs += $(sort $(dir $(LOCAL_GENERATED_SOURCES)))
 cts_src_dirs := $(addprefix -s , $(cts_src_dirs))
 
-$(cts_library_jar): PRIVATE_MODULE := $(LOCAL_MODULE)
-$(cts_library_jar): $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_MODULE))/javalib.jar | $(ACP)
-	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
-	$(hide) $(ACP) -fp $(call intermediates-dir-for,JAVA_LIBRARIES,$(PRIVATE_MODULE))/javalib.jar $@
-
+cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
 $(cts_library_xml): PRIVATE_SRC_DIRS := $(cts_src_dirs)
 $(cts_library_xml): PRIVATE_TEST_APP_PACKAGE := $(LOCAL_CTS_TEST_APP_PACKAGE)
 $(cts_library_xml): PRIVATE_TEST_PACKAGE := $(LOCAL_CTS_TEST_PACKAGE)
 $(cts_library_xml): PRIVATE_TEST_APK := $(LOCAL_CTS_TEST_APK)
 $(cts_library_xml): PRIVATE_LIBRARY := $(LOCAL_MODULE)
 $(cts_library_xml): PRIVATE_JAR_PATH := $(LOCAL_MODULE).jar
-$(cts_library_xml): $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_MODULE))/javalib.jar $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
+$(cts_library_xml): $(cts_library_jar)
+$(cts_library_xml): $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for uiautomator library $(PRIVATE_LIBRARY)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 	$(hide) $(CTS_JAVA_TEST_SCANNER) $(PRIVATE_SRC_DIRS) \
diff --git a/common/util/src/com/android/compatibility/common/util/MetricsReportLog.java b/common/util/src/com/android/compatibility/common/util/MetricsReportLog.java
new file mode 100644
index 0000000..4675231
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/MetricsReportLog.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+/**
+ * A {@link ReportLog} that can be used with the in memory metrics store used for host side metrics.
+ */
+public final class MetricsReportLog extends ReportLog {
+    private final String mDeviceSerial;
+    private final String mAbi;
+    private final String mClassMethodName;
+
+    /**
+     * @param deviceSerial serial number of the device
+     * @param abi abi the test was run on
+     * @param classMethodName class name and method name of the test in class#method format.
+     *        Note that ReportLog.getClassMethodNames() provide this.
+     */
+    public MetricsReportLog(String deviceSerial, String abi, String classMethodName) {
+        mDeviceSerial = deviceSerial;
+        mAbi = abi;
+        mClassMethodName = classMethodName;
+    }
+
+    public void submit() {
+        MetricsStore.storeResult(mDeviceSerial, mAbi, mClassMethodName, this);
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/MetricsStore.java b/common/util/src/com/android/compatibility/common/util/MetricsStore.java
new file mode 100644
index 0000000..9eeb94a
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/MetricsStore.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A simple in-memory store for metrics results. This should be used for hostside metrics reporting.
+ */
+public class MetricsStore {
+
+    // needs concurrent version as there can be multiple client accessing this.
+    // But there is no additional protection for the same key as that should not happen.
+    private static final ConcurrentHashMap<String, ReportLog> mMap =
+            new ConcurrentHashMap<String, ReportLog>();
+
+    /**
+     * Stores a result. Existing result with the same key will be replaced.
+     * Note that key is generated in the form of device_serial#class#method name.
+     * So there should be no concurrent test for the same (serial, class, method).
+     * @param deviceSerial
+     * @param abi
+     * @param classMethodName
+     * @param reportLog Contains the result to be stored
+     */
+    public static void storeResult(
+            String deviceSerial, String abi, String classMethodName, ReportLog reportLog) {
+        mMap.put(generateTestKey(deviceSerial, abi, classMethodName), reportLog);
+    }
+
+    /**
+     * retrieves a metric result for the given condition and remove it from the internal
+     * storage. If there is no result for the given condition, it will return null.
+     */
+    public static ReportLog removeResult(String deviceSerial, String abi, String classMethodName) {
+        return mMap.remove(generateTestKey(deviceSerial, abi, classMethodName));
+    }
+
+    /**
+     * @return test key in the form of device_serial#abi#class_name#method_name
+     */
+    private static String generateTestKey(String deviceSerial, String abi, String classMethodName) {
+        return String.format("%s#%s#%s", deviceSerial, abi, classMethodName);
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ReportLog.java b/common/util/src/com/android/compatibility/common/util/ReportLog.java
index 8cfc086..7209ac8 100644
--- a/common/util/src/com/android/compatibility/common/util/ReportLog.java
+++ b/common/util/src/com/android/compatibility/common/util/ReportLog.java
@@ -16,28 +16,37 @@
 
 package com.android.compatibility.common.util;
 
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
 
 /**
  * Utility class to add results to the report.
  */
-public abstract class ReportLog implements Serializable {
+public class ReportLog implements Serializable {
 
+    private static final String LOG_SEPARATOR = "+++";
+    private static final String SUMMARY_SEPARATOR = "++++";
+    private static final String LOG_ELEM_SEPARATOR = "|";
+    private static final String EMPTY_CHAR = " ";
     private Result mSummary;
     private final List<Result> mDetails = new ArrayList<Result>();
 
-    class Result implements Serializable {
-        private static final int CALLER_STACKTRACE_DEPTH = 5;
+    static class Result implements Serializable {
         private String mLocation;
         private String mMessage;
         private double[] mValues;
         private ResultType mType;
         private ResultUnit mUnit;
+        private Double mTarget;
+
+
+        private Result(String location, String message, double[] values,
+                ResultType type, ResultUnit unit) {
+            this(location, message, values, null /*target*/, type, unit);
+        }
 
         /**
          * Creates a result object to be included in the report. Each object has a message
@@ -47,23 +56,22 @@
          *
          * @param message A string describing the values
          * @param values An array of the values
+         * @param target Nullable. The target value.
          * @param type Represents how to interpret the values (eg. A lower score is better)
          * @param unit Represents the unit in which the values are (eg. Milliseconds)
-         * @param depth A number used to increase the depth the stack is queried. This should only
-         * be given in the case that the report is populated by a helper function, in which case it
-         * would be 1, or else 0.
          */
-        private Result(String message, double[] values, ResultType type,
-                ResultUnit unit, int depth) {
-            final StackTraceElement[] trace = Thread.currentThread().getStackTrace();
-            final StackTraceElement e =
-                    trace[Math.min(CALLER_STACKTRACE_DEPTH + depth, trace.length - 1)];
-            mLocation = String.format(
-                    "%s#%s:%d", e.getClassName(), e.getMethodName(), e.getLineNumber());
+        private Result(String location, String message, double[] values,
+                Double target, ResultType type, ResultUnit unit) {
+            mLocation = location;
             mMessage = message;
             mValues = values;
             mType = type;
             mUnit = unit;
+            mTarget = target;
+        }
+
+        public double getTarget() {
+            return mTarget;
         }
 
         public String getLocation() {
@@ -85,51 +93,89 @@
         public ResultUnit getUnit() {
             return mUnit;
         }
+
+        /**
+         * Format:
+         * location|message|target|type|unit|value[s], target can be " " if there is no target set.
+         * log for array = classMethodName:line_number|message|unit|type|space separated values
+         */
+        String toEncodedString() {
+            StringBuilder builder = new StringBuilder()
+                    .append(mLocation)
+                    .append(LOG_ELEM_SEPARATOR)
+                    .append(mMessage)
+                    .append(LOG_ELEM_SEPARATOR)
+                    .append(mTarget != null ? mTarget : EMPTY_CHAR)
+                    .append(LOG_ELEM_SEPARATOR)
+                    .append(mType.name())
+                    .append(LOG_ELEM_SEPARATOR)
+                    .append(mUnit.name())
+                    .append(LOG_ELEM_SEPARATOR);
+            for (double value : mValues) {
+                builder.append(value).append(" ");
+            }
+            return builder.toString();
+        }
+
+        static Result fromEncodedString(String encodedString) {
+            String[] elems = encodedString.split(Pattern.quote(LOG_ELEM_SEPARATOR));
+            if (elems.length < 5) {
+                return null;
+            }
+
+            String[] valueStrArray = elems[5].split(" ");
+            double[] valueArray = new double[valueStrArray.length];
+            for (int i = 0; i < valueStrArray.length; i++) {
+                valueArray[i] = Double.parseDouble(valueStrArray[i]);
+            }
+            return new Result(
+                    elems[0], /*location*/
+                    elems[1], /*message*/
+                    valueArray, /*values*/
+                    elems[2].equals(EMPTY_CHAR) ? null : Double.parseDouble(elems[2]), /*target*/
+                    ResultType.valueOf(elems[3]), /*type*/
+                    ResultUnit.valueOf(elems[4])  /*unit*/);
+        }
     }
 
     /**
      * Adds an array of values to the report.
      */
     public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
-        mDetails.add(new Result(message, values, type, unit, 0));
+        mDetails.add(new Result(Stacktrace.getTestCallerClassMethodNameLineNumber(),
+                message, values, type, unit));
     }
 
     /**
      * Adds an array of values to the report.
      */
-    public void addValues(String message, double[] values, ResultType type,
-            ResultUnit unit, int depth) {
-        mDetails.add(new Result(message, values, type, unit, depth));
+    public void addValues(
+            String message, double[] values, ResultType type, ResultUnit unit, String location) {
+        mDetails.add(new Result(location, message, values, type, unit));
     }
 
     /**
      * Adds a value to the report.
      */
     public void addValue(String message, double value, ResultType type, ResultUnit unit) {
-        mDetails.add(new Result(message, new double[] {value}, type, unit, 0));
+        mDetails.add(new Result(Stacktrace.getTestCallerClassMethodNameLineNumber(), message,
+                new double[] {value}, type, unit));
     }
 
     /**
      * Adds a value to the report.
      */
     public void addValue(String message, double value, ResultType type,
-            ResultUnit unit, int depth) {
-        mDetails.add(new Result(message, new double[] {value}, type, unit, depth));
+            ResultUnit unit, String location) {
+        mDetails.add(new Result(location, message, new double[] {value}, type, unit));
     }
 
     /**
      * Sets the summary of the report.
      */
     public void setSummary(String message, double value, ResultType type, ResultUnit unit) {
-        mSummary = new Result(message, new double[] {value}, type, unit, 0);
-    }
-
-    /**
-     * Sets the summary of the report.
-     */
-    public void setSummary(String message, double value, ResultType type,
-            ResultUnit unit, int depth) {
-        mSummary = new Result(message, new double[] {value}, type, unit, depth);
+        mSummary = new Result(Stacktrace.getTestCallerClassMethodNameLineNumber(),
+                message, new double[] {value}, type, unit);
     }
 
     public Result getSummary() {
@@ -139,4 +185,46 @@
     public List<Result> getDetailedMetrics() {
         return new ArrayList<Result>(mDetails);
     }
+
+    /**
+     * Parse a String encoded {@link com.android.compatibility.common.util.ReportLog}
+     */
+    public static ReportLog fromEncodedString(String encodedString) {
+        ReportLog reportLog = new ReportLog();
+        StringTokenizer tok = new StringTokenizer(encodedString, SUMMARY_SEPARATOR);
+        if (tok.hasMoreTokens()) {
+            // Extract the summary
+            reportLog.mSummary = Result.fromEncodedString(tok.nextToken());
+        }
+        if (tok.hasMoreTokens()) {
+            // Extract the detailed results
+            StringTokenizer detailedTok = new StringTokenizer(tok.nextToken(), LOG_SEPARATOR);
+            while (detailedTok.hasMoreTokens()) {
+                reportLog.mDetails.add(Result.fromEncodedString(detailedTok.nextToken()));
+            }
+        }
+        return reportLog;
+    }
+
+    /**
+     * @return a String representation of this report or null if not collected
+     */
+    protected String toEncodedString() {
+        if ((mSummary == null) && mDetails.isEmpty()) {
+            // just return empty string
+            return null;
+        }
+        StringBuilder builder = new StringBuilder();
+        builder.append(mSummary.toEncodedString());
+        builder.append(SUMMARY_SEPARATOR);
+        for (Result result : mDetails) {
+            builder.append(result.toEncodedString());
+            builder.append(LOG_SEPARATOR);
+        }
+        // delete the last separator
+        if (builder.length() >= LOG_SEPARATOR.length()) {
+            builder.delete(builder.length() - LOG_SEPARATOR.length(), builder.length());
+        }
+        return builder.toString();
+    }
 }
diff --git a/common/util/src/com/android/compatibility/common/util/Stacktrace.java b/common/util/src/com/android/compatibility/common/util/Stacktrace.java
new file mode 100644
index 0000000..27bf9ca
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/Stacktrace.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+/**
+ * Helper methods for dealing with stack traces
+ */
+public class Stacktrace {
+
+    private static final int SAFETY_DEPTH = 4;
+    private static final String TEST_POSTFIX = "Test";
+
+    private Stacktrace() {}
+
+    /**
+     * @return classname#methodname from call stack of the current thread
+     */
+    public static String getTestCallerClassMethodName() {
+        return getTestCallerClassMethodName(false /*includeLineNumber*/);
+    }
+
+    /**
+     * @return classname#methodname from call stack of the current thread
+     */
+    public static String getTestCallerClassMethodNameLineNumber() {
+        return getTestCallerClassMethodName(true /*includeLineNumber*/);
+    }
+
+    /**
+     * @return classname#methodname from call stack of the current thread
+     */
+    private static String getTestCallerClassMethodName(boolean includeLineNumber) {
+        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
+        // Look for the first class name in the elements array that ends with Test
+        for (int i = 0; i < elements.length; i++) {
+            if (elements[i].getClassName().endsWith(TEST_POSTFIX)) {
+                return buildClassMethodName(elements, i, includeLineNumber);
+            }
+        }
+
+        // Use a reasonable default if the test name isn't found
+        return buildClassMethodName(elements, SAFETY_DEPTH, includeLineNumber);
+    }
+
+    private static String buildClassMethodName(
+            StackTraceElement[] elements, int depth, boolean includeLineNumber) {
+        depth = Math.min(depth, elements.length - 1);
+        StringBuilder builder = new StringBuilder();
+        builder.append(elements[depth].getClassName()).append("#")
+                .append(elements[depth].getMethodName());
+        if (includeLineNumber) {
+            builder.append(":").append(elements[depth].getLineNumber());
+        }
+        return builder.toString();
+    }
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/MetricsStoreTest.java b/common/util/tests/src/com/android/compatibility/common/util/MetricsStoreTest.java
new file mode 100644
index 0000000..944cc43
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/MetricsStoreTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link MetricsStore}
+ */
+public class MetricsStoreTest extends TestCase {
+
+    private static final String DEVICE_SERIAL = "DEVICE_SERIAL";
+    private static final String ABI = "ABI";
+    private static final String CLASSMETHOD_NAME = "CLASSMETHOD_NAME";
+
+    private static final double[] VALUES = new double[] {1, 11, 21, 1211, 111221};
+
+    private ReportLog mReportLog;
+
+    @Override
+    protected void setUp() throws Exception {
+        this.mReportLog = new ReportLog();
+    }
+
+    public void testStoreAndRemove() {
+        mReportLog.setSummary("Sample Summary", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
+        MetricsStore.storeResult(DEVICE_SERIAL, ABI, CLASSMETHOD_NAME, mReportLog);
+
+        ReportLog reportLog = MetricsStore.removeResult(DEVICE_SERIAL, ABI, CLASSMETHOD_NAME);
+        assertSame(mReportLog, reportLog);
+        assertNull(MetricsStore.removeResult("blah", ABI, CLASSMETHOD_NAME));
+    }
+
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java b/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
index 70da820..05e69d8 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
@@ -36,7 +36,8 @@
             HEADER
             + "<Summary message=\"Sample\" scoreType=\"higher_better\" unit=\"byte\">1.0</Summary>"
             + "<Details>"
-                    + "<ValueArray source=\"sun.reflect.NativeMethodAccessorImpl#invoke0:-2\""
+                    + "<ValueArray source=\"com.android.compatibility.common.util."
+                    + "MetricsXmlSerializerTest#testSerialize:84\""
                     + " message=\"Details\" scoreType=\"neutral\" unit=\"fps\">"
                         + "<Value>1.0</Value>"
                         + "<Value>11.0</Value>"
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
new file mode 100644
index 0000000..a5f3306
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link ReportLog}
+ */
+public class ReportLogTest extends TestCase {
+
+    private static final double[] VALUES = new double[] {1, 11, 21, 1211, 111221};
+
+    private static final String EXPECTED_ENCODED_REPORT_LOG =
+            "com.android.compatibility.common.util.ReportLogTest#testEncodeDecode:44|" +
+            "Sample Summary| |HIGHER_BETTER|BYTE|1.0 ++++" +
+            "com.android.compatibility.common.util.ReportLogTest#testEncodeDecode:45|" +
+            "Details| |NEUTRAL|FPS|1.0 11.0 21.0 1211.0 111221.0 ";
+    private ReportLog reportLog;
+
+    @Override
+    protected void setUp() throws Exception {
+        this.reportLog = new ReportLog();
+    }
+
+    public void testEncodeDecode() {
+
+        reportLog.setSummary("Sample Summary", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        reportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
+
+        String encodedReportLog = reportLog.toEncodedString();
+        assertEquals(EXPECTED_ENCODED_REPORT_LOG, encodedReportLog);
+
+        ReportLog decodedReportLog = ReportLog.fromEncodedString(encodedReportLog);
+        ReportLog.Result summary = reportLog.getSummary();
+        assertEquals("Sample Summary", summary.getMessage());
+        assertFalse(summary.getLocation().isEmpty());
+        assertEquals(ResultType.HIGHER_BETTER, summary.getType());
+        assertEquals(ResultUnit.BYTE, summary.getUnit());
+        assertTrue(Arrays.equals(new double[] {1.0}, summary.getValues()));
+
+        assertEquals(1, decodedReportLog.getDetailedMetrics().size());
+        ReportLog.Result detail = decodedReportLog.getDetailedMetrics().get(0);
+        assertEquals("Details", detail.getMessage());
+        assertFalse(detail.getLocation().isEmpty());
+        assertEquals(ResultType.NEUTRAL, detail.getType());
+        assertEquals(ResultUnit.FPS, detail.getUnit());
+        assertTrue(Arrays.equals(VALUES, detail.getValues()));
+
+        assertEquals(encodedReportLog, decodedReportLog.toEncodedString());
+    }
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
index b9a17e1..348c680 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
@@ -26,6 +26,8 @@
     public UnitTests() {
         super();
 
+        addTestSuite(MetricsStoreTest.class);
         addTestSuite(MetricsXmlSerializerTest.class);
+        addTestSuite(ReportLogTest.class);
     }
 }
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
index 4d9ef00..206bdbe 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
@@ -20,7 +20,6 @@
 import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.InstrumentationResultParser;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
 import com.android.ddmlib.testrunner.TestResult.TestStatus;
@@ -107,6 +106,8 @@
 
     private static final String LOG_TAG = "AppSecurityTests";
 
+    private static final int USER_OWNER = 0;
+
     private IAbi mAbi;
     private CtsBuildHelper mCtsBuild;
 
@@ -224,6 +225,7 @@
      * Verify that app with no external storage permissions works correctly.
      */
     public void testExternalStorageNone() throws Exception {
+        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage(getDevice());
 
@@ -231,10 +233,14 @@
             String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
             assertNull(getDevice()
                     .installPackage(getTestAppFile(EXTERNAL_STORAGE_APP_APK), false, options));
-            assertTrue("Failed external storage with no permissions",
-                    runDeviceTests(EXTERNAL_STORAGE_APP_PKG));
+
+            for (int user : users) {
+                assertTrue("Failed external storage with no permissions",
+                        runDeviceTests(EXTERNAL_STORAGE_APP_PKG, user));
+            }
         } finally {
             getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+            removeUsersForTest(users);
         }
     }
 
@@ -244,6 +250,7 @@
      * correctly.
      */
     public void testExternalStorageRead() throws Exception {
+        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage(getDevice());
 
@@ -251,10 +258,14 @@
             String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
             assertNull(getDevice()
                     .installPackage(getTestAppFile(READ_EXTERNAL_STORAGE_APP_APK), false, options));
-            assertTrue("Failed external storage with read permissions",
-                    runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG));
+
+            for (int user : users) {
+                assertTrue("Failed external storage with read permissions",
+                        runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG, user));
+            }
         } finally {
             getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
+            removeUsersForTest(users);
         }
     }
 
@@ -264,6 +275,7 @@
      * correctly.
      */
     public void testExternalStorageWrite() throws Exception {
+        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage(getDevice());
 
@@ -271,10 +283,14 @@
             String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
             assertNull(getDevice()
                     .installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false, options));
-            assertTrue("Failed external storage with write permissions",
-                    runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG));
+
+            for (int user : users) {
+                assertTrue("Failed external storage with write permissions",
+                        runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG, user));
+            }
         } finally {
             getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+            removeUsersForTest(users);
         }
     }
 
@@ -283,6 +299,7 @@
      * directories belonging to other apps, and those apps can read.
      */
     public void testExternalStorageGifts() throws Exception {
+        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage(getDevice());
 
@@ -297,18 +314,19 @@
             assertNull(getDevice()
                     .installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false, options));
 
-            assertTrue("Failed to write gifts", runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG,
-                    WRITE_EXTERNAL_STORAGE_APP_CLASS, "doWriteGifts"));
-
-            assertTrue("Read failed to verify gifts", runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG,
-                    READ_EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts"));
-            assertTrue("None failed to verify gifts", runDeviceTests(EXTERNAL_STORAGE_APP_PKG,
-                    EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts"));
-
+            for (int user : users) {
+                assertTrue("Failed to write gifts", runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG,
+                        WRITE_EXTERNAL_STORAGE_APP_CLASS, "doWriteGifts", user));
+                assertTrue("Read failed to verify gifts", runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG,
+                        READ_EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts", user));
+                assertTrue("None failed to verify gifts", runDeviceTests(EXTERNAL_STORAGE_APP_PKG,
+                        EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts", user));
+            }
         } finally {
             getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
             getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
             getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+            removeUsersForTest(users);
         }
     }
 
@@ -409,7 +427,7 @@
             assertNull(String.format("failed to install permission app with diff cert. Reason: %s",
                     installResult), installResult);
             // run PERMISSION_DIFF_CERT_PKG tests which try to access the permission
-            TestRunResult result = doRunTests(PERMISSION_DIFF_CERT_PKG, null, null);
+            TestRunResult result = doRunTests(PERMISSION_DIFF_CERT_PKG, null, null, USER_OWNER);
             assertDeviceTestsPass(result);
         }
         finally {
@@ -423,20 +441,19 @@
      * Test multi-user emulated storage environment, ensuring that each user has
      * isolated storage.
      */
-    public void testMultiUserStorage() throws Exception {
+    public void testMultiUserStorageIsolated() throws Exception {
         final String PACKAGE = MULTIUSER_STORAGE_PKG;
         final String CLAZZ = MULTIUSER_STORAGE_CLASS;
 
-        if (!isMultiUserSupportedOnDevice(getDevice())) {
-            Log.d(LOG_TAG, "Single user device; skipping isolated storage tests");
-            return;
-        }
-
-        int owner = 0;
-        int secondary = -1;
+        final int[] users = createUsersForTest();
         try {
-            // Create secondary user
-            secondary = createUserOnDevice(getDevice());
+            if (users.length == 1) {
+                Log.d(LOG_TAG, "Single user device; skipping isolated storage tests");
+                return;
+            }
+
+            final int owner = users[0];
+            final int secondary = users[1];
 
             // Install our test app
             getDevice().uninstallPackage(MULTIUSER_STORAGE_PKG);
@@ -447,26 +464,24 @@
 
             // Clear data from previous tests
             assertDeviceTestsPass(
-                    doRunTestsAsUser(PACKAGE, CLAZZ, "cleanIsolatedStorage", owner));
+                    doRunTests(PACKAGE, CLAZZ, "cleanIsolatedStorage", owner));
             assertDeviceTestsPass(
-                    doRunTestsAsUser(PACKAGE, CLAZZ, "cleanIsolatedStorage", secondary));
+                    doRunTests(PACKAGE, CLAZZ, "cleanIsolatedStorage", secondary));
 
             // Have both users try writing into isolated storage
             assertDeviceTestsPass(
-                    doRunTestsAsUser(PACKAGE, CLAZZ, "writeIsolatedStorage", owner));
+                    doRunTests(PACKAGE, CLAZZ, "writeIsolatedStorage", owner));
             assertDeviceTestsPass(
-                    doRunTestsAsUser(PACKAGE, CLAZZ, "writeIsolatedStorage", secondary));
+                    doRunTests(PACKAGE, CLAZZ, "writeIsolatedStorage", secondary));
 
             // Verify they both have isolated view of storage
             assertDeviceTestsPass(
-                    doRunTestsAsUser(PACKAGE, CLAZZ, "readIsolatedStorage", owner));
+                    doRunTests(PACKAGE, CLAZZ, "readIsolatedStorage", owner));
             assertDeviceTestsPass(
-                    doRunTestsAsUser(PACKAGE, CLAZZ, "readIsolatedStorage", secondary));
+                    doRunTests(PACKAGE, CLAZZ, "readIsolatedStorage", secondary));
         } finally {
             getDevice().uninstallPackage(MULTIUSER_STORAGE_PKG);
-            if (secondary != -1) {
-                removeUserOnDevice(getDevice(), secondary);
-            }
+            removeUsersForTest(users);
         }
     }
 
@@ -504,7 +519,11 @@
      * @throws DeviceNotAvailableException if connection to device was lost.
      */
     private boolean runDeviceTests(String pkgName) throws DeviceNotAvailableException {
-        return runDeviceTests(pkgName, null, null);
+        return runDeviceTests(pkgName, null, null, USER_OWNER);
+    }
+
+    private boolean runDeviceTests(String pkgName, int userId) throws DeviceNotAvailableException {
+        return runDeviceTests(pkgName, null, null, userId);
     }
 
     /**
@@ -516,28 +535,14 @@
      */
     private boolean runDeviceTests(String pkgName, String testClassName, String testMethodName)
             throws DeviceNotAvailableException {
-        TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName);
-        return !runResult.hasFailedTests();
+        return runDeviceTests(pkgName, testClassName, testMethodName, USER_OWNER);
     }
 
-    /**
-     * Helper method to run tests and return the listener that collected the results.
-     *
-     * @param pkgName Android application package for tests
-     * @return the {@link TestRunResult}
-     * @throws DeviceNotAvailableException if connection to device was lost.
-     */
-    private TestRunResult doRunTests(String pkgName, String testClassName,
-            String testMethodName) throws DeviceNotAvailableException {
-
-        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName,
-                RUNNER, getDevice().getIDevice());
-        if (testClassName != null && testMethodName != null) {
-            testRunner.setMethodName(testClassName, testMethodName);
-        }
-        CollectingTestListener listener = new CollectingTestListener();
-        getDevice().runInstrumentationTests(testRunner, listener);
-        return listener.getCurrentRunResults();
+    private boolean runDeviceTests(String pkgName, String testClassName, String testMethodName,
+            int userId) throws DeviceNotAvailableException {
+        TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName,
+                userId);
+        return !runResult.hasFailedTests();
     }
 
     private static boolean isMultiUserSupportedOnDevice(ITestDevice device)
@@ -552,13 +557,38 @@
         return false;
     }
 
+    /**
+     * Return set of users that test should be run for, creating a secondary
+     * user if the device supports it. Always call
+     * {@link #removeUsersForTest(int[])} when finished.
+     */
+    private int[] createUsersForTest() throws DeviceNotAvailableException {
+        if (isMultiUserSupportedOnDevice(getDevice())) {
+            return new int[] { USER_OWNER, createUserOnDevice(getDevice()) };
+        } else {
+            Log.d(LOG_TAG, "Single user device; skipping isolated storage tests");
+            return new int[] { USER_OWNER };
+        }
+    }
+
+    private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
+        for (int user : users) {
+            if (user != USER_OWNER) {
+                removeUserOnDevice(getDevice(), user);
+            }
+        }
+   }
+
     private static int createUserOnDevice(ITestDevice device) throws DeviceNotAvailableException {
         // TODO: move this to ITestDevice once it supports users
         final String name = "CTS_" + System.currentTimeMillis();
         final String output = device.executeShellCommand("pm create-user " + name);
         if (output.startsWith("Success")) {
             try {
-                return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
+                final int userId = Integer.parseInt(
+                        output.substring(output.lastIndexOf(" ")).trim());
+                device.executeShellCommand("am start-user " + userId);
+                return userId;
             } catch (NumberFormatException e) {
                 fail("Failed to parse result: " + output);
             }
@@ -577,18 +607,24 @@
         }
     }
 
-    private TestRunResult doRunTestsAsUser(
-            String pkgName, String testClassName, String testMethodName, int userId)
-            throws DeviceNotAvailableException {
+    private TestRunResult doRunTests(String pkgName, String testClassName, String testMethodName,
+            int userId) throws DeviceNotAvailableException {
         // TODO: move this to RemoteAndroidTestRunner once it supports users
-        final String cmd = "am instrument --user " + userId + " -w -r -e class " + testClassName
-                + "#" + testMethodName + " " + pkgName + "/" + RUNNER;
+        final StringBuilder cmd = new StringBuilder("am instrument --user " + userId + " -w -r");
+        if (testClassName != null) {
+            cmd.append(" -e class " + testClassName);
+            if (testMethodName != null) {
+                cmd.append("#" + testMethodName);
+            }
+        }
+        cmd.append(" " + pkgName + "/" + RUNNER);
+
         Log.i(LOG_TAG, "Running " + cmd + " on " + getDevice().getSerialNumber());
 
         CollectingTestListener listener = new CollectingTestListener();
         InstrumentationResultParser parser = new InstrumentationResultParser(pkgName, listener);
 
-        getDevice().executeShellCommand(cmd, parser);
+        getDevice().executeShellCommand(cmd.toString(), parser);
         return listener.getCurrentRunResults();
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
index 2c9c624..4459e69 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
index 098ce9c..0916254 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
@@ -29,4 +29,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
index 910e3cd..272ef28 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
@@ -31,4 +31,4 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
index a886fb2..bbf7734 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
@@ -31,4 +31,4 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
index afc8764..a7de92a 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
@@ -25,4 +25,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index 5b4d9f7..aa09f75 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -21,13 +21,17 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -43,6 +47,14 @@
     public static final String PACKAGE_WRITE = "com.android.cts.writeexternalstorageapp";
 
     /**
+     * Dump helpful debugging details.
+     */
+    public void testDumpDebug() throws Exception {
+        logCommand("/system/bin/id");
+        logCommand("/system/bin/cat", "/proc/self/mountinfo");
+    }
+
+    /**
      * Primary storage must always be mounted.
      */
     public void testExternalStorageMounted() {
@@ -315,7 +327,9 @@
             }
 
             File[] dirs = removeWhiteList(dir.listFiles());
-            assertEquals(0, dirs.length);
+            if (dirs.length != 0) {
+                fail("Expected wiped storage but found: " + Arrays.toString(dirs));
+            }
         }
     }
 
@@ -336,4 +350,27 @@
             is.close();
         }
     }
+
+    private static void logCommand(String... cmd) throws Exception {
+        final Process proc = new ProcessBuilder(cmd).redirectErrorStream(true).start();
+
+        final ByteArrayOutputStream buf = new ByteArrayOutputStream();
+        copy(proc.getInputStream(), buf);
+        final int res = proc.waitFor();
+
+        Log.d(TAG, Arrays.toString(cmd) + " result " + res + ":");
+        Log.d(TAG, buf.toString());
+    }
+
+    /** Shamelessly lifted from libcore.io.Streams */
+    public static int copy(InputStream in, OutputStream out) throws IOException {
+        int total = 0;
+        byte[] buffer = new byte[8192];
+        int c;
+        while ((c = in.read(buffer)) != -1) {
+            total += c;
+            out.write(buffer, 0, c);
+        }
+        return total;
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
index e8ce3b8..4c64204 100644
--- a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
index 1dd109a..c37d052 100644
--- a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
@@ -27,4 +27,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
index 60d6fad..43d3547 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
index ba7285c..5109c99 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
index 3e392e3..c662d39 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
@@ -27,4 +27,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
index 76187ab..05438ef 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
@@ -32,4 +32,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
index c1422ec..eaed910 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
index fb925cd..01cffdb 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
index 2224d72..032ef57 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
index bf89576..de46dea 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
@@ -35,7 +35,7 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 
 #################################################
@@ -59,7 +59,7 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 
 ################################################
@@ -82,7 +82,7 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 
 ################################################
@@ -105,7 +105,7 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 
 ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
index 809a6b8..fbb7764 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -35,4 +35,4 @@
 
 LOCAL_AAPT_FLAGS += --feature-of $(featureOfApk)
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
index 543e4ac..9faaba1 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
@@ -25,4 +25,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
index 7cdef62..87b32aa 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
@@ -25,4 +25,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
index 26ec5bd..fe289e0 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
@@ -25,4 +25,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
index fea0603..d66d674 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
@@ -25,4 +25,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
index 3cc5609..7232324 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
@@ -25,4 +25,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
index d45ca8f..f1cd994 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
@@ -25,4 +25,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
index fa0e488..521f6f2 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
@@ -25,4 +25,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
index 38a0511..f5ac52f 100644
--- a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
index 8878c47..6e0d090 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
@@ -31,4 +31,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
index a98fcea..cdd77e8 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
@@ -27,4 +27,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 6857236..afee8541 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -93,6 +93,17 @@
         assertEquals(readInt(TEST_FILE), 32);
     }
 
+    public void testWriteExternalStorageDirs() throws Exception {
+        final File probe = new File(
+                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
+                "100CTS");
+
+        assertFalse(probe.exists());
+        assertTrue(probe.mkdirs());
+
+        assertDirReadWriteAccess(probe);
+    }
+
     /**
      * Verify that legacy filesystem paths continue working, and that they all
      * point to same location.
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
index 715905a..f5a7286 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed cts-keyset-test-b
 include $(CLEAR_VARS)
@@ -36,4 +36,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
index eceea38..678d89d 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed cts-keyset-test-b
 include $(CLEAR_VARS)
@@ -36,4 +36,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
index ed6db690..b8acc99 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
@@ -23,4 +23,4 @@
 LOCAL_PACKAGE_NAME := CtsKeySetTestApp
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
index efba345..4d441de 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed by cts-keyset-test-b
 include $(CLEAR_VARS)
@@ -35,7 +35,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed by cts-keyset-test-a and cts-keyset-test-b
 include $(CLEAR_VARS)
@@ -47,4 +47,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
index 219689e..406529c 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
@@ -24,4 +24,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
index 040c378..23d6b17 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
@@ -24,4 +24,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
index 62b5461..f2cedf9 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed cts-keyset-test-b
 include $(CLEAR_VARS)
@@ -36,7 +36,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed by cts-keyset-test-a and cts-keyset-test-c
 include $(CLEAR_VARS)
@@ -49,4 +49,4 @@
 LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
index 5fc4ab9..9b327fe 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
@@ -24,4 +24,4 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index e621933..bd0089f 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -26,6 +26,8 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index dfc7e9c..6aa6bbb 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -61,7 +61,7 @@
             android:name="com.android.cts.deviceowner.ApplicationRestrictionActivity" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.cts.deviceowner"
                      android:label="Device Owner CTS tests"/>
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ApplicationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ApplicationRestrictionsTest.java
index 5e03de9..13a2a6d 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ApplicationRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ApplicationRestrictionsTest.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
+import android.os.Parcelable;
 
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -106,7 +107,7 @@
     // Should be consistent with assertBundle0
     private Bundle createBundle0() {
         Bundle result = new Bundle();
-        // Tests for four allowed types: Integer, Boolean, String and String[]
+        // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
         // Also test for string escaping handling
         result.putBoolean("boolean_0", false);
         result.putBoolean("boolean_1", true);
@@ -115,12 +116,28 @@
         result.putString("empty", "");
         result.putString("string", "text");
         result.putStringArray("string[]", testStrings);
+
+        // Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
+        Bundle bundle = new Bundle();
+        bundle.putString("bundle_string", "bundle_string");
+        bundle.putInt("bundle_int", 1);
+        result.putBundle("bundle", bundle);
+
+        // Adding an array of 2 bundles
+        Bundle[] bundleArray = new Bundle[2];
+        bundleArray[0] = new Bundle();
+        bundleArray[0].putString("bundle_array_string", "bundle_array_string");
+        // Put bundle inside bundle
+        bundleArray[0].putBundle("bundle_array_bundle", bundle);
+        bundleArray[1] = new Bundle();
+        bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
+        result.putParcelableArray("bundle_array", bundleArray);
         return result;
     }
 
     // Should be consistent with createBundle0
     private void assertBundle0(Bundle bundle) {
-        assertEquals(6, bundle.size());
+        assertEquals(8, bundle.size());
         assertEquals(false, bundle.getBoolean("boolean_0"));
         assertEquals(true, bundle.getBoolean("boolean_1"));
         assertEquals(0x7fffffff, bundle.getInt("integer"));
@@ -132,6 +149,23 @@
         for (int i = 0; i < strings.length; i++) {
             assertEquals(strings[i], testStrings[i]);
         }
+
+        Bundle childBundle = bundle.getBundle("bundle");
+        assertEquals("bundle_string", childBundle.getString("bundle_string"));
+        assertEquals(1, childBundle.getInt("bundle_int"));
+
+        Parcelable[] bundleArray = bundle.getParcelableArray("bundle_array");
+        assertEquals(2, bundleArray.length);
+        // Verifying bundle_array[0]
+        Bundle bundle1 = (Bundle) bundleArray[0];
+        assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
+        Bundle bundle1ChildBundle = bundle1.getBundle("bundle_array_bundle");
+        assertNotNull(bundle1ChildBundle);
+        assertEquals("bundle_string", bundle1ChildBundle.getString("bundle_string"));
+        assertEquals(1, bundle1ChildBundle.getInt("bundle_int"));
+        // Verifying bundle_array[1]
+        Bundle bundle2 = (Bundle) bundleArray[1];
+        assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
     }
 
     // Should be consistent with assertBundle1
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index fe2bdda..23d108f 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -34,11 +34,13 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        // Enable credential storage by setting a nonempty password.
         assertTrue(mDevicePolicyManager.resetPassword("test", 0));
     }
 
     @Override
     protected void tearDown() throws Exception {
+        // Delete all keys by resetting our password to null, which clears the keystore.
         mDevicePolicyManager.setPasswordQuality(getWho(),
                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
         mDevicePolicyManager.setPasswordMinimumLength(getWho(), 0);
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
index e45ec31..e5246c5 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctstestrunner
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml b/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml
index 070ef40..cc27298 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml
@@ -52,7 +52,7 @@
     </application>
 
     <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
+        android:name="android.support.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.cts.intent.sender"
         android:label="Intent Sender CTS Tests" />
 
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/CopyPasteTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/CopyPasteTest.java
index a5d83db..46fc0c4 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/CopyPasteTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/CopyPasteTest.java
@@ -44,7 +44,7 @@
         super.setUp();
         Context context = getInstrumentation().getTargetContext();
         mActivity = launchActivity(context.getPackageName(), IntentSenderActivity.class, null);
-        mClipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+        mClipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
     }
 
     @Override
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index 46e3cf7..f4adb31 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index e430785..aeb6a45 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -75,7 +75,7 @@
         <activity android:name=".TestActivity" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.cts.managedprofile"
                      android:label="Managed Profile CTS Tests"/>
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
index 49001e9..21b2d36 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
@@ -40,8 +40,8 @@
 
     private static String ACTION_COPY_TO_CLIPBOARD = "com.android.cts.action.COPY_TO_CLIPBOARD";
 
-    public void addParentCanAccessManagedFilters() {
-        removeAllFilters();
+    public void testAddParentCanAccessManagedFilters() {
+        testRemoveAllFilters();
 
         final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
@@ -49,8 +49,8 @@
                 DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
     }
 
-    public void addManagedCanAccessParentFilters() {
-        removeAllFilters();
+    public void testAddManagedCanAccessParentFilters() {
+        testRemoveAllFilters();
 
         final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
@@ -67,20 +67,20 @@
         return intentFilter;
     }
 
-    public void removeAllFilters() {
+    public void testRemoveAllFilters() {
         final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
         dpm.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT);
     }
 
-    public void disallowCrossProfileCopyPaste() {
+    public void testDisallowCrossProfileCopyPaste() {
         DevicePolicyManager dpm = (DevicePolicyManager)
                getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
         dpm.addUserRestriction(ADMIN_RECEIVER_COMPONENT,
                 UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
     }
 
-    public void allowCrossProfileCopyPaste() {
+    public void testAllowCrossProfileCopyPaste() {
         DevicePolicyManager dpm = (DevicePolicyManager)
                getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
         dpm.clearUserRestriction(ADMIN_RECEIVER_COMPONENT,
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
index 47ecfcb..e655d7b 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
@@ -21,6 +21,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
 
 import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
 
@@ -43,6 +44,10 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        // As the way to access Instrumentation is changed in the new runner, we need to inject it
+        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+        // be marked as deprecated and replaced with ActivityTestRule.
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
         mPackageManager = getActivity().getPackageManager();
         mDevicePolicyManager = (DevicePolicyManager)
                 getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
index 40ff6c5..4163ba8 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
 
 /**
  * Test for {@link DevicePolicyManager#addCrossProfileIntentFilter} API, for
@@ -43,6 +44,10 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        // As the way to access Instrumentation is changed in the new runner, we need to inject it
+        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+        // be marked as deprecated and replaced with ActivityTestRule.
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
         mPackageManager = getActivity().getPackageManager();
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 5149a74..c0e6479 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -47,13 +47,13 @@
  */
 public class BaseDevicePolicyTest extends DeviceTestCase implements IBuildReceiver {
 
+    private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
+
     protected static final String MANAGED_PROFILE_PKG = "com.android.cts.managedprofile";
     protected static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
     protected static final String ADMIN_RECEIVER_TEST_CLASS =
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
 
-    private static final String RUNNER = "android.test.InstrumentationTestRunner";
-
     private CtsBuildHelper mCtsBuild;
 
     private HashSet<String> mAvailableFeatures;
@@ -152,6 +152,14 @@
         Thread.sleep(60 * 1000);
     }
 
+    protected void removeTestUsers() throws Exception {
+        for (int userId : listUsers()) {
+            if (userId != 0) {
+                removeUser(userId);
+            }
+        }
+    }
+
     /** Returns true if the specified tests passed. Tests are run as user owner. */
     protected boolean runDeviceTests(String pkgName, @Nullable String testClassName)
             throws DeviceNotAvailableException {
@@ -300,7 +308,6 @@
         return Integer.parseInt(tokens[tokens.length-1]);
     }
 
-
     protected int getUserSerialNumber(int userId) throws DeviceNotAvailableException{
         // dumpsys user return lines like "UserInfo{0:Owner:13} serialNo=0"
         String commandOutput = getDevice().executeShellCommand("dumpsys user");
@@ -322,7 +329,7 @@
 
     protected void setProfileOwner(String componentName, int userId)
             throws DeviceNotAvailableException {
-        String command = "dpm set-profile-owner '" + componentName + "' " + userId;
+        String command = "dpm set-profile-owner --user " + userId + " '" + componentName + "'";
         String commandOutput = getDevice().executeShellCommand(command);
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
         assertTrue(commandOutput + " expected to start with \"Success:\"",
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseLauncherAppsTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseLauncherAppsTest.java
index dec8bd2..b106ffd 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseLauncherAppsTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseLauncherAppsTest.java
@@ -45,14 +45,6 @@
         getDevice().uninstallPackage(SIMPLE_APP_PKG);
     }
 
-    protected void removeTestUsers() throws Exception {
-        for (int userId : listUsers()) {
-            if (userId != 0) {
-                removeUser(userId);
-            }
-        }
-    }
-
     protected void startCallbackService() throws Exception {
         String command = "am startservice --user 0 "
                 + "-a " + LAUNCHER_TESTS_SUPPORT_PKG + ".REGISTER_CALLBACK "
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 862322a..2926b2b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -49,6 +49,7 @@
                 "android.software.managed_users");
 
         if (mHasFeature) {
+            removeTestUsers();
             mUserId = createManagedProfile();
             installApp(MANAGED_PROFILE_APK);
             installApp(INTENT_RECEIVER_APK);
@@ -136,16 +137,16 @@
 
         // Test from parent to managed
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "removeAllFilters", mUserId));
+                "testRemoveAllFilters", mUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "addManagedCanAccessParentFilters", mUserId));
+                "testAddManagedCanAccessParentFilters", mUserId));
         assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", 0));
 
         // Test from managed to parent
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "removeAllFilters", mUserId));
+                "testRemoveAllFilters", mUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "addParentCanAccessManagedFilters", mUserId));
+                "testAddParentCanAccessManagedFilters", mUserId));
         assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mUserId));
 
     }
@@ -156,14 +157,14 @@
         }
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "allowCrossProfileCopyPaste", mUserId));
+                "testAllowCrossProfileCopyPaste", mUserId));
         // Test that managed can see what is copied in the parent.
         testCrossProfileCopyPasteInternal(mUserId, true);
         // Test that the parent can see what is copied in managed.
         testCrossProfileCopyPasteInternal(0, true);
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "disallowCrossProfileCopyPaste", mUserId));
+                "testDisallowCrossProfileCopyPaste", mUserId));
         // Test that managed can still see what is copied in the parent.
         testCrossProfileCopyPasteInternal(mUserId, true);
         // Test that the parent cannot see what is copied in managed.
@@ -172,10 +173,11 @@
 
     private void testCrossProfileCopyPasteInternal(int userId, boolean shouldSucceed)
             throws DeviceNotAvailableException {
-        final String direction = (userId == 0) ? "addManagedCanAccessParentFilters"
-                : "addParentCanAccessManagedFilters";
+        final String direction = (userId == 0)
+                ? "testAddManagedCanAccessParentFilters"
+                : "testAddParentCanAccessManagedFilters";
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "removeAllFilters", mUserId));
+                "testRemoveAllFilters", mUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
                 direction, mUserId));
         if (shouldSucceed) {
@@ -197,6 +199,9 @@
         if (!mHasFeature) {
             return;
         }
+        // If adb is running as root, then the adb uid is 0 instead of SHELL_UID,
+        // so the DISALLOW_DEBUGGING_FEATURES restriction does not work and this test
+        // fails.
         String restriction = "no_debugging_features";  // UserManager.DISALLOW_DEBUGGING_FEATURES
         String command = "add-restriction";
 
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
index f6543fb..c04d4b2 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
index 29bf9d6..b3cb181 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/net/app/Android.mk b/hostsidetests/net/app/Android.mk
index 29b620d..055287a 100644
--- a/hostsidetests/net/app/Android.mk
+++ b/hostsidetests/net/app/Android.mk
@@ -29,4 +29,4 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/libs/commonutil/src/com/android/cts/util/ReportLog.java b/libs/commonutil/src/com/android/cts/util/ReportLog.java
index 56b431a..dd4b414 100644
--- a/libs/commonutil/src/com/android/cts/util/ReportLog.java
+++ b/libs/commonutil/src/com/android/cts/util/ReportLog.java
@@ -42,26 +42,55 @@
 
     /**
      * print array of values to output log
+     * <p>Note: test identifier is inferred from call stack trace based on class and method name
      */
     public void printArray(String message, double[] values, ResultType type, ResultUnit unit) {
         doPrintArray(message, values, type, unit);
     }
 
     /**
+     * print array of values to output log
+     */
+    public void printArray(String testId, String message,
+            double[] values, ResultType type, ResultUnit unit) {
+        doPrintArray(testId, message, values, type, unit);
+    }
+
+    /**
      * Print a value to output log
+     * <p>Note: test identifier is inferred from call stack trace based on class and method name
      */
     public void printValue(String message, double value, ResultType type, ResultUnit unit) {
         double[] vals = { value };
         doPrintArray(message, vals, type, unit);
     }
 
+    /**
+     * Print a value to output log
+     */
+    public void printValue(String testId, String message,
+            double value, ResultType type, ResultUnit unit) {
+        double[] vals = { value };
+        doPrintArray(testId, message, vals, type, unit);
+    }
+
     private void doPrintArray(String message, double[] values, ResultType type, ResultUnit unit) {
+        doPrintArray(getClassMethodNames(mDepth + 1, true), message, values, type, unit);
+    }
+
+    private void doPrintArray(String testId, String message,
+            double[] values, ResultType type, ResultUnit unit) {
         StringBuilder builder = new StringBuilder();
         // note mDepth + 1 as this function will be called by printVaue or printArray
         // and we need caller of printValue / printArray
-        builder.append(getClassMethodNames(mDepth + 1, true) + LOG_ELEM_SEPARATOR + message +
-                LOG_ELEM_SEPARATOR + type.getXmlString() + LOG_ELEM_SEPARATOR +
-                unit.getXmlString() + LOG_ELEM_SEPARATOR);
+        builder.append(testId);
+        builder.append(LOG_ELEM_SEPARATOR);
+        builder.append(message);
+        builder.append(LOG_ELEM_SEPARATOR);
+        builder.append(type.getXmlString());
+        builder.append(LOG_ELEM_SEPARATOR);
+        builder.append(unit.getXmlString());
+        builder.append(LOG_ELEM_SEPARATOR);
         for (double v : values) {
             builder.append(v);
             builder.append(" ");
diff --git a/libs/deviceutil/src/android/cts/util/SystemUtil.java b/libs/deviceutil/src/android/cts/util/SystemUtil.java
index e6222cb..6e7fd38 100644
--- a/libs/deviceutil/src/android/cts/util/SystemUtil.java
+++ b/libs/deviceutil/src/android/cts/util/SystemUtil.java
@@ -18,9 +18,14 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.MemoryInfo;
+import android.app.Instrumentation;
 import android.content.Context;
+import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
 
+import java.io.FileInputStream;
+import java.io.IOException;
+
 public class SystemUtil {
     public static long getFreeDiskSize(Context context) {
         StatFs statFs = new StatFs(context.getFilesDir().getAbsolutePath());
@@ -40,4 +45,28 @@
         activityManager.getMemoryInfo(info);
         return info.totalMem; // TODO totalMem N/A in ICS.
     }
+
+    /**
+     * Executes a shell command using shell user identity, and return the standard output in string
+     * <p>Note: calling this function requires API level 21 or above
+     * @param instrumentation {@link Instrumentation} instance, obtained from a test running in
+     * instrumentation framework
+     * @param cmd the command to run
+     * @return the standard output of the command
+     * @throws Exception
+     */
+    public static String runShellCommand(Instrumentation instrumentation, String cmd)
+            throws IOException {
+        ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
+        byte[] buf = new byte[512];
+        int bytesRead;
+        FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        StringBuffer stdout = new StringBuffer();
+        while ((bytesRead = fis.read(buf)) != -1) {
+            stdout.append(new String(buf, 0, bytesRead));
+        }
+        fis.close();
+        return stdout.toString();
+    }
+
 }
diff --git a/libs/testserver/Android.mk b/libs/testserver/Android.mk
index dfe357b..488af53 100644
--- a/libs/testserver/Android.mk
+++ b/libs/testserver/Android.mk
@@ -22,4 +22,6 @@
 
 LOCAL_MODULE := ctstestserver
 
+LOCAL_SDK_VERSION := 16
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/libs/testserver/src/android/webkit/cts/CtsTestServer.java b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
index 22cbb7b..e39e435 100644
--- a/libs/testserver/src/android/webkit/cts/CtsTestServer.java
+++ b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
@@ -15,7 +15,6 @@
  */
 package android.webkit.cts;
 
-import libcore.io.Base64;
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
@@ -44,6 +43,7 @@
 import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Environment;
+import android.util.Base64;
 import android.util.Log;
 import android.webkit.MimeTypeMap;
 
@@ -947,7 +947,7 @@
          * for the result.
          */
         private static KeyManager[] getKeyManagers() throws Exception {
-            byte[] bytes = Base64.decode(SERVER_KEYS_BKS.getBytes());
+            byte[] bytes = Base64.decode(SERVER_KEYS_BKS.getBytes(), Base64.DEFAULT);
             InputStream inputStream = new ByteArrayInputStream(bytes);
 
             KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/suite/cts/deviceTests/jank2/Android.mk b/suite/cts/deviceTests/jank2/Android.mk
new file mode 100644
index 0000000..346297e
--- /dev/null
+++ b/suite/cts/deviceTests/jank2/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsJankTestCases
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator ub-janktesthelper
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/suite/cts/deviceTests/jank2/AndroidManifest.xml b/suite/cts/deviceTests/jank2/AndroidManifest.xml
new file mode 100644
index 0000000..a4c8337
--- /dev/null
+++ b/suite/cts/deviceTests/jank2/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.cts.jank">
+
+  <application>
+      <uses-library android:name="android.test.runner"/>
+  </application>
+
+  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                   android:targetPackage="android.cts.jank"
+                   android:label="Jank tests">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/suite/cts/deviceTests/jank2/AndroidTest.xml b/suite/cts/deviceTests/jank2/AndroidTest.xml
new file mode 100644
index 0000000..2fbbac7
--- /dev/null
+++ b/suite/cts/deviceTests/jank2/AndroidTest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="CTS Jank test config">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsDeviceUi.apk" />
+</configuration>
diff --git a/suite/cts/deviceTests/jank2/src/android/cts/jank/CtsJankTestBase.java b/suite/cts/deviceTests/jank2/src/android/cts/jank/CtsJankTestBase.java
new file mode 100644
index 0000000..cb5c122
--- /dev/null
+++ b/suite/cts/deviceTests/jank2/src/android/cts/jank/CtsJankTestBase.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.cts.jank;
+
+import android.cts.util.DeviceReportLog;
+import android.os.Bundle;
+import android.support.test.jank.JankTestBase;
+import android.support.test.jank.WindowContentFrameStatsMonitor;
+import android.support.test.uiautomator.UiDevice;
+
+import com.android.cts.util.ResultType;
+import com.android.cts.util.ResultUnit;
+
+public abstract class CtsJankTestBase extends JankTestBase {
+
+    private UiDevice mDevice;
+    private DeviceReportLog mLog;
+
+    @Override
+    public void afterTest(Bundle metrics) {
+        String source = String.format("%s#%s", getClass().getCanonicalName(), getName());
+        mLog.printValue(source, WindowContentFrameStatsMonitor.KEY_AVG_FPS,
+                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_FPS),
+                ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        mLog.printValue(source, WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME,
+                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        mLog.printValue(source, WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY,
+                metrics.getInt(WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY),
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        mLog.printSummary(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY,
+                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY),
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mLog = new DeviceReportLog();
+        // fix device orientation
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        mDevice.setOrientationNatural();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mLog.deliverReportToHost(getInstrumentation());
+        // restore device orientation
+        mDevice.unfreezeRotation();
+        super.tearDown();
+    }
+
+    protected UiDevice getUiDevice() {
+        return mDevice;
+    }
+}
diff --git a/suite/cts/deviceTests/jank2/src/android/cts/jank/ui/CtsDeviceJankUi.java b/suite/cts/deviceTests/jank2/src/android/cts/jank/ui/CtsDeviceJankUi.java
new file mode 100644
index 0000000..884f83c
--- /dev/null
+++ b/suite/cts/deviceTests/jank2/src/android/cts/jank/ui/CtsDeviceJankUi.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.cts.jank.ui;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.cts.jank.CtsJankTestBase;
+import android.os.SystemClock;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.WindowContentFrameStatsMonitor;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.Until;
+import android.widget.ListView;
+
+import java.io.IOException;
+
+public class CtsDeviceJankUi extends CtsJankTestBase {
+    private final static int NUM_ELEMENTS = 1000;
+    private static final long DEFAULT_ANIMATION_TIME = 2 * 1000;
+    private static final long POST_SCROLL_IDLE_TIME = 2 *1000;
+    private final static String PACKAGE = "com.android.cts.ui";
+    private final static String CLASS = PACKAGE + ".ScrollingActivity";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // launch the activity as part of the set up
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setComponent(new ComponentName(PACKAGE, CLASS));
+        intent.putExtra("num_elements", NUM_ELEMENTS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getInstrumentation().getTargetContext().startActivity(intent);
+        getUiDevice().wait(Until.hasObject(By.pkg(PACKAGE)), DEFAULT_ANIMATION_TIME);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getUiDevice().pressHome();
+        super.tearDown();
+    }
+
+    @JankTest(expectedFrames=50, defaultIterationCount=5)
+    @WindowContentFrameStatsMonitor
+    public void testScrolling() throws IOException {
+        getUiDevice().findObject(By.clazz(ListView.class)).fling(Direction.DOWN);
+        SystemClock.sleep(POST_SCROLL_IDLE_TIME);
+    }
+}
diff --git a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/ui/CtsDeviceJankUi.java b/suite/cts/hostTests/jank/app/src/com/android/cts/jank/ui/CtsDeviceJankUi.java
deleted file mode 100644
index ea1f685..0000000
--- a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/ui/CtsDeviceJankUi.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.cts.jank.ui;
-
-import android.util.Log;
-import android.widget.ListView;
-
-import com.android.cts.jank.CtsJankTestBase;
-import com.android.uiautomator.core.UiScrollable;
-import com.android.uiautomator.core.UiSelector;
-import com.android.uiautomator.platform.SurfaceFlingerHelper;
-
-public class CtsDeviceJankUi extends CtsJankTestBase {
-    private final static String TAG = CtsDeviceJankUi.class.getName();
-    private final static String PACKAGE = "com.android.cts.ui";
-    private final static String COMPONENT =
-            PACKAGE + "/" + PACKAGE + ".ScrollingActivity";
-    private final static int NUM_ELEMENTS = 1000;
-    private static String APP_WINDOW_NAME = COMPONENT;
-
-    // TODO(stuartscott): expand deviceTests/ui app to have a more complex UI
-    /**
-     * Runs the ScrollingActivity and measures jank during a scroll.
-     */
-    public void testScrolling() throws Exception {
-        // Start activity command
-        final StringBuilder sb = new StringBuilder();
-        sb.append(String.format(START_CMD, COMPONENT));
-        sb.append(String.format(INTENT_INTEGER_EXTRA, "num_elements", NUM_ELEMENTS));
-        final String startCommand = sb.toString();
-        final String stopCommand = String.format(STOP_CMD, PACKAGE);
-
-        Log.i(TAG, "Start command: " + startCommand);
-        Log.i(TAG, "Stop command: " + stopCommand);
-
-        setIteration(NUM_ITERATIONS);
-        for (int i = 0; i < NUM_ITERATIONS; i++) {
-            // Stop any existing instances
-            runShellCommand(stopCommand);
-            // Start activity
-            runShellCommand(startCommand);
-
-            // Wait for the activity to start
-            sleep(SLEEP_TIME / 2);
-
-            UiScrollable list = new UiScrollable(
-                    new UiSelector().className(ListView.class.getName()));
-
-            // Start systrace
-            startTrace(mTestCaseName, i);
-
-            // Clear SurfaceFlinger buffer
-            Log.i(TAG, "Clearing SurfaceFlinger buffer");
-            SurfaceFlingerHelper.clearBuffer(APP_WINDOW_NAME);
-
-            list.flingToEnd(2);
-
-            // Dump SurfaceFlinger buffer
-            Log.i(TAG, "Dumping SurfaceFlinger buffer");
-            boolean result = SurfaceFlingerHelper.dumpFrameLatency(APP_WINDOW_NAME, true);
-            assertTrue("SurfaceFlingerHelper could not get timestamps", result);
-
-            // Stop systrace
-            endTrace();
-
-            // Record results
-            recordResults(mTestCaseName, i);
-        }
-        // Save aggregated results
-        saveResults(mTestCaseName);
-        // Stop any remaining instances
-        runShellCommand(stopCommand);
-    }
-}
diff --git a/suite/cts/hostTests/jank/src/com/android/cts/jank/ui/CtsHostJankUi.java b/suite/cts/hostTests/jank/src/com/android/cts/jank/ui/CtsHostJankUi.java
deleted file mode 100644
index a07171e..0000000
--- a/suite/cts/hostTests/jank/src/com/android/cts/jank/ui/CtsHostJankUi.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.cts.jank.ui;
-
-import com.android.cts.jank.CtsHostJankTest;
-import com.android.cts.util.AbiUtils;
-import java.io.File;
-
-public class CtsHostJankUi extends CtsHostJankTest {
-
-    private static final String APK_PACKAGE = "com.android.cts";
-    private static final String APK = "CtsDeviceUi.apk";
-    private static final String PACKAGE = "com.android.cts.jank.ui";
-    private static final String HOST_CLASS = CtsHostJankUi.class.getName();
-    private static final String DEVICE_CLASS = PACKAGE + ".CtsDeviceJankUi";
-    private static final String JAR_NAME = "CtsDeviceJank.jar";
-
-    public CtsHostJankUi() {
-        super(JAR_NAME, DEVICE_CLASS, HOST_CLASS);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Install the app.
-        mDevice.uninstallPackage(APK_PACKAGE);
-        File app = mBuild.getTestApp(APK);
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        mDevice.installPackage(app, false, options);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // Uninstall the app.
-        mDevice.uninstallPackage(APK_PACKAGE);
-        super.tearDown();
-    }
-
-    public void testScrolling() throws Exception {
-        runUiAutomatorTest("testScrolling");
-    }
-}
diff --git a/suite/cts/hostTests/uihost/appA/Android.mk b/suite/cts/hostTests/uihost/appA/Android.mk
index 3e76fdb..17f076f 100644
--- a/suite/cts/hostTests/uihost/appA/Android.mk
+++ b/suite/cts/hostTests/uihost/appA/Android.mk
@@ -26,8 +26,6 @@
 
 LOCAL_PACKAGE_NAME := CtsDeviceTaskswitchingAppA
 
-LOCAL_SDK_VERSION := 16
+LOCAL_SDK_VERSION := current
 
-include $(BUILD_CTS_PACKAGE)
-
-
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/suite/cts/hostTests/uihost/appB/Android.mk b/suite/cts/hostTests/uihost/appB/Android.mk
index 13af40f..ebb36d2 100644
--- a/suite/cts/hostTests/uihost/appB/Android.mk
+++ b/suite/cts/hostTests/uihost/appB/Android.mk
@@ -26,8 +26,6 @@
 
 LOCAL_PACKAGE_NAME := CtsDeviceTaskswitchingAppB
 
-LOCAL_SDK_VERSION := 16
+LOCAL_SDK_VERSION := current
 
-include $(BUILD_CTS_PACKAGE)
-
-
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/suite/cts/hostTests/uihost/control/Android.mk b/suite/cts/hostTests/uihost/control/Android.mk
index 3770918..4de9ae8 100644
--- a/suite/cts/hostTests/uihost/control/Android.mk
+++ b/suite/cts/hostTests/uihost/control/Android.mk
@@ -26,6 +26,6 @@
 
 LOCAL_PACKAGE_NAME := CtsDeviceTaskswitchingControl
 
-LOCAL_SDK_VERSION := 16
+LOCAL_SDK_VERSION := current
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/suite/cts/hostTests/uihost/src/com/android/cts/uihost/TaskSwitchingTest.java b/suite/cts/hostTests/uihost/src/com/android/cts/uihost/TaskSwitchingTest.java
index 894b824..2d33436 100644
--- a/suite/cts/hostTests/uihost/src/com/android/cts/uihost/TaskSwitchingTest.java
+++ b/suite/cts/hostTests/uihost/src/com/android/cts/uihost/TaskSwitchingTest.java
@@ -115,7 +115,9 @@
         @Override
         public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
             // necessary as testMetrics passed from CollectingTestListerner is empty
-            mCtsReport = testMetrics.get("CTS_TEST_RESULT");
+            if (testMetrics.containsKey("CTS_TEST_RESULT")) {
+                mCtsReport = testMetrics.get("CTS_TEST_RESULT");
+            }
             super.testEnded(test, testMetrics);
         }
     }
diff --git a/tests/acceleration/Android.mk b/tests/acceleration/Android.mk
index a6d6022..f36b64b 100644
--- a/tests/acceleration/Android.mk
+++ b/tests/acceleration/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/accessibility/Android.mk b/tests/accessibility/Android.mk
index 43fa291..bddbb58 100644
--- a/tests/accessibility/Android.mk
+++ b/tests/accessibility/Android.mk
@@ -28,4 +28,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/app/Android.mk b/tests/app/Android.mk
index 69bf590..f4f0a13 100644
--- a/tests/app/Android.mk
+++ b/tests/app/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_PROGUARD_ENABLED := disabled
 
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common org.apache.http.legacy
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver
 
@@ -32,4 +32,4 @@
 
 LOCAL_PACKAGE_NAME := CtsAppTestStubs
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/app/AndroidManifest.xml b/tests/app/AndroidManifest.xml
index 0d61e20..8d7729e 100644
--- a/tests/app/AndroidManifest.xml
+++ b/tests/app/AndroidManifest.xml
@@ -49,6 +49,7 @@
                 android:name="android.app.cts.MockApplication"
                 android:supportsRtl="true">
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
 
         <activity android:name="android.app.cts.ActionBarActivity" />
 
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 080c08e..d7bda32 100644
--- a/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java
+++ b/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.support.test.internal.runner.listener.InstrumentationRunListener;
+import android.text.TextUtils;
 import android.util.Log;
 
 import junit.framework.TestCase;
@@ -28,7 +29,10 @@
 import org.junit.runner.Description;
 import org.junit.runner.notification.RunListener;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.net.Authenticator;
@@ -114,6 +118,31 @@
         Log.d(TAG, "Total memory  : " + total);
         Log.d(TAG, "Used memory   : " + used);
         Log.d(TAG, "Free memory   : " + free);
+
+        String tempdir = System.getProperty("java.io.tmpdir", "");
+        if (!TextUtils.isEmpty(tempdir)) {
+            String[] commands = {"df", tempdir};
+            BufferedReader in = null;
+            try {
+                Process proc = runtime.exec(commands);
+                in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+                String line;
+                while ((line = in.readLine()) != null) {
+                    Log.d(TAG, line);
+                }
+            } catch (IOException e) {
+                // Well, we tried
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+                    } catch (IOException e) {
+                        // Meh
+                    }
+                }
+            }
+        }
+
         Log.d(TAG, "Now executing : " + testClass.getName());
     }
 
@@ -161,8 +190,8 @@
             mSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
 
             mProperties.setProperty("user.home", "");
-            mProperties.setProperty("java.io.tmpdir", System.getProperty("java.io.tmpdir"));
-            // The CDD mandates that devices that support WiFi are the only ones that will have 
+            mProperties.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath());
+            // The CDD mandates that devices that support WiFi are the only ones that will have
             // multicast.
             PackageManager pm = context.getPackageManager();
             mProperties.setProperty("android.cts.device.multicast",
diff --git a/tests/deviceadmin/Android.mk b/tests/deviceadmin/Android.mk
index 9ab9cb8..2e89d34 100644
--- a/tests/deviceadmin/Android.mk
+++ b/tests/deviceadmin/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 72a2811..6e571a7 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -7,13 +7,6 @@
   bug: 17536113
 },
 {
-  description: "the ConnectivityConstraintTest are not yet stable",
-  names: [
-    "android.jobscheduler.cts.ConnectivityConstraintTest"
-  ],
-  bug: 18117279
-},
-{
   description: "tests a fragile by nature as they rely on hardcoded behavior",
   names: [
     "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverText",
@@ -76,6 +69,26 @@
   bug: 16720689
 },
 {
+  description: "test can only run properly on a user build device when the bug is resolved",
+  names: [
+    "android.appwidget.cts.AppWidgetTest#testAppWidgetProviderCallbacks",
+    "android.appwidget.cts.AppWidgetTest#testBindAppWidget",
+    "android.appwidget.cts.AppWidgetTest#testCollectionWidgets",
+    "android.appwidget.cts.AppWidgetTest#testDeleteHost",
+    "android.appwidget.cts.AppWidgetTest#testDeleteHosts",
+    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetIds",
+    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetInfo",
+    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetOptions",
+    "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetId",
+    "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetIds",
+    "android.appwidget.cts.AppWidgetTest#testTwoAppWidgetProviderCallbacks",
+    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaComponentName",
+    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetId",
+    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetIds"
+  ],
+  bug: 17993121
+},
+{
   description: "A few WebGL tests are known to fail in WebView",
   names: [
     "android.webgl.cts.WebGLTest#test_conformance_extensions_oes_texture_float_with_video_html",
diff --git a/tests/print/Android.mk b/tests/print/Android.mk
deleted file mode 100644
index fea7dc0..0000000
--- a/tests/print/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-##################################################
-# Build the print instrument library
-##################################################
-include $(CLEAR_VARS)
-LOCAL_MODULE := CtsPrintInstrument
-LOCAL_SRC_FILES := $(call all-subdir-java-files) \
-    src/android/print/cts/IPrivilegedOperations.aidl
-LOCAL_MODULE_TAGS := optional
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_JAVA_LIBRARY)
-
-# Copy the shell script to run the print instrument Jar to the CTS out folder.
-$(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar : $(LOCAL_BUILT_MODULE) | $(ACP) 
-	$(copy-file-to-target)
-
-# Copy the built print instrument library Jar to the CTS out folder.
-$(CTS_TESTCASES_OUT)/print-instrument : $(LOCAL_PATH)/print-instrument | $(ACP)
-	$(copy-file-to-target)
-
diff --git a/tests/print/print-instrument b/tests/print/print-instrument
deleted file mode 100755
index a79cb8a..0000000
--- a/tests/print/print-instrument
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-# Script to start "print-instrument" on the device
-#
-# The script sets up an alternative dalvik cache when running as
-# non-root. Jar files needs to be dexopt'd to run in Dalvik. For
-# plain jar files, this is done at first use. shell user does not
-# have write permission to default system Dalvik cache so we
-# redirect to an alternative cache.
-
-RUN_BASE=/data/local/tmp
-
-# If not running as root, use an alternative dex cache.
-if [ ${USER_ID} -ne 0 ]; then
-  tmp_cache=${RUN_BASE}/dalvik-cache
-  if [ ! -d ${tmp_cache} ]; then
-    mkdir -p ${tmp_cache}
-  fi
-  export ANDROID_DATA=${RUN_BASE}
-fi
-
-# Run print-instrument.
-export CLASSPATH=${RUN_BASE}/CtsPrintInstrument.jar
-
-exec app_process ${RUN_BASE} android.print.cts.PrintInstrument ${@}
diff --git a/tests/print/src/android/print/cts/PrintInstrument.java b/tests/print/src/android/print/cts/PrintInstrument.java
deleted file mode 100644
index 1c568a1..0000000
--- a/tests/print/src/android/print/cts/PrintInstrument.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * 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 android.print.cts;
-
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
-import android.app.IInstrumentationWatcher;
-import android.app.Instrumentation;
-import android.app.UiAutomationConnection;
-import android.content.ComponentName;
-import android.content.pm.IPackageDataObserver;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.util.AndroidException;
-import android.view.IWindowManager;
-
-import com.android.internal.os.BaseCommand;
-
-import java.io.PrintStream;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public final class PrintInstrument extends BaseCommand {
-
-    private static final String ARG_PRIVILEGED_OPS = "ARG_PRIVILEGED_OPS";
-
-    private IActivityManager mAm;
-
-    public static void main(String[] args) {
-        PrintInstrument instrumenter = new PrintInstrument();
-        instrumenter.run(args);
-    }
-
-    @Override
-    public void onRun() throws Exception {
-        mAm = ActivityManagerNative.getDefault();
-        if (mAm == null) {
-            System.err.println(NO_SYSTEM_ERROR_CODE);
-            throw new AndroidException("Can't connect to activity manager;"
-                    + " is the system running?");
-        }
-
-        String op = nextArgRequired();
-
-        if (op.equals("instrument")) {
-            runInstrument();
-        } else {
-            showError("Error: unknown command '" + op + "'");
-        }
-    }
-
-    @Override
-    public void onShowUsage(PrintStream out) {
-        /* do nothing */
-    }
-
-    @SuppressWarnings("deprecation")
-    private void runInstrument() throws Exception {
-        String profileFile = null;
-        boolean wait = false;
-        boolean rawMode = false;
-        boolean no_window_animation = false;
-        int userId = UserHandle.USER_CURRENT;
-        Bundle args = new Bundle();
-        String argKey = null, argValue = null;
-        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
-
-        String opt;
-        while ((opt=nextOption()) != null) {
-            if (opt.equals("-p")) {
-                profileFile = nextArgRequired();
-            } else if (opt.equals("-w")) {
-                wait = true;
-            } else if (opt.equals("-r")) {
-                rawMode = true;
-            } else if (opt.equals("-e")) {
-                argKey = nextArgRequired();
-                argValue = nextArgRequired();
-                args.putString(argKey, argValue);
-            } else if (opt.equals("--no_window_animation")
-                    || opt.equals("--no-window-animation")) {
-                no_window_animation = true;
-            } else if (opt.equals("--user")) {
-                userId = parseUserArg(nextArgRequired());
-            } else {
-                System.err.println("Error: Unknown option: " + opt);
-                return;
-            }
-        }
-
-        if (userId == UserHandle.USER_ALL) {
-            System.err.println("Error: Can't start instrumentation with user 'all'");
-            return;
-        }
-
-        String cnArg = nextArgRequired();
-        ComponentName cn = ComponentName.unflattenFromString(cnArg);
-        if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
-
-        InstrumentationWatcher watcher = null;
-        UiAutomationConnection connection = null;
-        if (wait) {
-            watcher = new InstrumentationWatcher();
-            watcher.setRawOutput(rawMode);
-            connection = new UiAutomationConnection();
-        }
-
-        float[] oldAnims = null;
-        if (no_window_animation) {
-            oldAnims = wm.getAnimationScales();
-            wm.setAnimationScale(0, 0.0f);
-            wm.setAnimationScale(1, 0.0f);
-        }
-
-        args.putIBinder(ARG_PRIVILEGED_OPS, new PrivilegedOperations(mAm));
-
-        if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, null)) {
-            throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
-        }
-
-        if (watcher != null) {
-            if (!watcher.waitForFinish()) {
-                System.out.println("INSTRUMENTATION_ABORTED: System has crashed.");
-            }
-        }
-
-        if (oldAnims != null) {
-            wm.setAnimationScales(oldAnims);
-        }
-    }
-
-    private int parseUserArg(String arg) {
-        int userId;
-        if ("all".equals(arg)) {
-            userId = UserHandle.USER_ALL;
-        } else if ("current".equals(arg) || "cur".equals(arg)) {
-            userId = UserHandle.USER_CURRENT;
-        } else {
-            userId = Integer.parseInt(arg);
-        }
-        return userId;
-    }
-
-    private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
-        private boolean mFinished = false;
-        private boolean mRawMode = false;
-
-        /**
-         * Set or reset "raw mode".  In "raw mode", all bundles are dumped.  In "pretty mode",
-         * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
-         * @param rawMode true for raw mode, false for pretty mode.
-         */
-        public void setRawOutput(boolean rawMode) {
-            mRawMode = rawMode;
-        }
-
-        @Override
-        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
-            synchronized (this) {
-                // pretty printer mode?
-                String pretty = null;
-                if (!mRawMode && results != null) {
-                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
-                }
-                if (pretty != null) {
-                    System.out.print(pretty);
-                } else {
-                    if (results != null) {
-                        for (String key : results.keySet()) {
-                            System.out.println(
-                                    "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key));
-                        }
-                    }
-                    System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
-                }
-                notifyAll();
-            }
-        }
-
-        @Override
-        public void instrumentationFinished(ComponentName name, int resultCode,
-                Bundle results) {
-            synchronized (this) {
-                // pretty printer mode?
-                String pretty = null;
-                if (!mRawMode && results != null) {
-                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
-                }
-                if (pretty != null) {
-                    System.out.println(pretty);
-                } else {
-                    if (results != null) {
-                        for (String key : results.keySet()) {
-                            System.out.println(
-                                    "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
-                        }
-                    }
-                    System.out.println("INSTRUMENTATION_CODE: " + resultCode);
-                }
-                mFinished = true;
-                notifyAll();
-            }
-        }
-
-        public boolean waitForFinish() {
-            synchronized (this) {
-                while (!mFinished) {
-                    try {
-                        if (!mAm.asBinder().pingBinder()) {
-                            return false;
-                        }
-                        wait(1000);
-                    } catch (InterruptedException e) {
-                        throw new IllegalStateException(e);
-                    }
-                }
-            }
-            return true;
-        }
-    }
-
-    private static final class PrivilegedOperations extends IPrivilegedOperations.Stub {
-        private final IActivityManager mAm;
-
-        public PrivilegedOperations(IActivityManager am) {
-            mAm = am;
-        }
-
-        @Override
-        public boolean clearApplicationUserData(final String clearedPackageName)
-                throws RemoteException {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                final AtomicBoolean success = new AtomicBoolean();
-                final CountDownLatch completionLatch = new CountDownLatch(1);
-
-                mAm.clearApplicationUserData(clearedPackageName,
-                        new IPackageDataObserver.Stub() {
-                            @Override
-                            public void onRemoveCompleted(String packageName, boolean succeeded) {
-                                if (clearedPackageName.equals(packageName) && succeeded) {
-                                    success.set(true);
-                                } else {
-                                    success.set(false);
-                                }
-                                completionLatch.countDown();
-                            }
-                }, UserHandle.USER_CURRENT);
-
-                try {
-                    completionLatch.await();
-                } catch (InterruptedException ie) {
-                    /* ignore */
-                }
-
-                return success.get();
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-}
diff --git a/tests/tests/accessibility/Android.mk b/tests/tests/accessibility/Android.mk
index 9f98b16..bb943ee 100644
--- a/tests/tests/accessibility/Android.mk
+++ b/tests/tests/accessibility/Android.mk
@@ -26,7 +26,4 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
 
-# This test runner sets up/cleans up the device before/after running the tests.
-LOCAL_CTS_TEST_RUNNER := com.android.cts.tradefed.testtype.AccessibilityTestRunner
-
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/accessibility/AndroidTest.xml b/tests/tests/accessibility/AndroidTest.xml
new file mode 100644
index 0000000..7832508
--- /dev/null
+++ b/tests/tests/accessibility/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Base config for CTS package preparer">
+    <include name="common-config" />
+    <option name="run-command:run-command" value="settings put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+    <option name="run-command:run-command" value="settings put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+    <option name="run-command:run-command" value="settings put secure accessibility_enabled 1" />
+    <option name="run-command:teardown-command" value="settings put secure enabled_accessibility_services &quot;&quot;" />
+    <option name="run-command:teardown-command" value="settings put secure touch_exploration_granted_accessibility_services &quot;&quot;" />
+    <option name="run-command:teardown-command" value="settings put secure accessibility_enabled 0" />
+    <option name="cts-apk-installer:test-file-name" value="CtsSomeAccessibilityServices.apk" />
+</configuration>
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index 39be0dc..4a3d31f 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -21,7 +21,7 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common org.apache.http.legacy
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver
 
diff --git a/tests/tests/app/AndroidManifest.xml b/tests/tests/app/AndroidManifest.xml
index 08b0dda..231727f 100644
--- a/tests/tests/app/AndroidManifest.xml
+++ b/tests/tests/app/AndroidManifest.xml
@@ -22,6 +22,7 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
new file mode 100644
index 0000000..08bbacd
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.cts;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.content.Context;
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test cases for Bluetooth LE scans.
+ * <p>
+ * To run the test, the device must be placed in an environment that has at least 5 BLE beacons
+ * broadcasting no slower than 1 HZ. The BLE beacons should be a combination of iBeacon devices and
+ * non-iBeacon devices.
+ * <p>
+ * Run 'run cts --class android.bluetooth.cts.BluetoothLeScanTest' in cts-tradefed to run the test
+ * cases.
+ */
+public class BluetoothLeScanTest extends AndroidTestCase {
+
+    private static final String TAG = "BluetoothLeScanTest";
+
+    private static final ScanFilter MANUFACTURER_DATA_FILTER =
+            new ScanFilter.Builder().setManufacturerData(0x004C, new byte[0], new byte[0]).build();
+    private static final int SCAN_DURATION_MILLIS = 5000;
+    private static final int BATCH_SCAN_REPORT_DELAY_MILLIS = 10000;
+
+    private BluetoothLeScanner mScanner;
+
+    @Override
+    public void setUp() {
+        BluetoothManager manager = (BluetoothManager) mContext.getSystemService(
+                Context.BLUETOOTH_SERVICE);
+        BluetoothAdapter adapter = manager.getAdapter();
+        if (!adapter.isEnabled()) {
+            adapter.enable();
+            // Note it's not reliable to listen for Adapter.ACTION_STATE_CHANGED broadcast and check
+            // bluetooth state.
+            sleep(2000);
+        }
+        mScanner = adapter.getBluetoothLeScanner();
+    }
+
+    /**
+     * Basic test case for BLE scans. Checks BLE scan timestamp is within correct range.
+     */
+    @MediumTest
+    public void testBasicBleScan() {
+        BleScanCallback regularLeScanCallback = new BleScanCallback();
+        long scanStartMillis = SystemClock.elapsedRealtime();
+        mScanner.startScan(regularLeScanCallback);
+        sleep(SCAN_DURATION_MILLIS);
+        mScanner.stopScan(regularLeScanCallback);
+        long scanEndMillis = SystemClock.elapsedRealtime();
+        Collection<ScanResult> scanResults = regularLeScanCallback.getScanResults();
+        assertTrue("Scan results shouldn't be empty", !scanResults.isEmpty());
+        verifyTimestamp(scanResults, scanStartMillis, scanEndMillis);
+    }
+
+    /**
+     * Test of scan filters. Ensures only beacons matching certain type of scan filters were
+     * reported.
+     */
+    @MediumTest
+    public void testScanFilter() {
+        List<ScanFilter> filters = new ArrayList<ScanFilter>();
+        filters.add(MANUFACTURER_DATA_FILTER);
+
+        BleScanCallback filterLeScanCallback = new BleScanCallback();
+        ScanSettings settings = new ScanSettings.Builder().setScanMode(
+                ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+        mScanner.startScan(filters, settings, filterLeScanCallback);
+        sleep(SCAN_DURATION_MILLIS);
+        mScanner.stopScan(filterLeScanCallback);
+        Collection<ScanResult> scanResults = filterLeScanCallback.getScanResults();
+        assertTrue("No scan results", !scanResults.isEmpty());
+        for (ScanResult result : scanResults) {
+            assertTrue(MANUFACTURER_DATA_FILTER.matches(result));
+        }
+    }
+
+    /**
+     * Test of opportunistic BLE scans.
+     */
+    @MediumTest
+    public void testOpportunisticScan() {
+        ScanSettings opportunisticScanSettings =
+                new ScanSettings.Builder()
+                        .setScanMode(-1) // TODO: use constants in ScanSettings once it's unhiden.
+                        .build();
+        BleScanCallback emptyScanCallback = new BleScanCallback();
+
+        // No scans are really started with opportunistic scans only.
+        mScanner.startScan(Collections.<ScanFilter> emptyList(), opportunisticScanSettings,
+                emptyScanCallback);
+        sleep(SCAN_DURATION_MILLIS);
+        assertTrue(emptyScanCallback.getScanResults().isEmpty());
+
+        BleScanCallback regularScanCallback = new BleScanCallback();
+        ScanSettings regularScanSettings =
+                new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+        List<ScanFilter> filters = new ArrayList<>();
+        filters.add(MANUFACTURER_DATA_FILTER);
+        mScanner.startScan(filters, regularScanSettings, regularScanCallback);
+        sleep(SCAN_DURATION_MILLIS);
+        // With normal BLE scan client, opportunistic scan client will get scan results.
+        assertTrue("opportunistic scan results shouldn't be empty",
+                !emptyScanCallback.getScanResults().isEmpty());
+        assertTrue("opportunistic scan should see more results",
+                emptyScanCallback.getScanResults().size() >
+                regularScanCallback.getScanResults().size());
+
+        // No more scan results for opportunistic scan clients once the normal BLE scan clients
+        // stops.
+        mScanner.stopScan(regularScanCallback);
+        // In case we got scan results before scan was completely stopped.
+        sleep(1000);
+        emptyScanCallback.clear();
+        sleep(SCAN_DURATION_MILLIS);
+        assertTrue("opportunistic scan shouldn't have scan results",
+                emptyScanCallback.getScanResults().isEmpty());
+    }
+
+    /**
+     * Test case for BLE Batch scan.
+     */
+    @MediumTest
+    public void testBatchScan() {
+        ScanSettings batchScanSettings = new ScanSettings.Builder()
+                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+                .setReportDelay(BATCH_SCAN_REPORT_DELAY_MILLIS).build();
+        BleScanCallback batchScanCallback = new BleScanCallback();
+        long scanStartMillis = SystemClock.elapsedRealtime();
+        mScanner.startScan(Collections.<ScanFilter> emptyList(), batchScanSettings,
+                batchScanCallback);
+        sleep(SCAN_DURATION_MILLIS);
+        mScanner.flushPendingScanResults(batchScanCallback);
+        sleep(1000);
+        long scanEndMillis = SystemClock.elapsedRealtime();
+        List<ScanResult> results = batchScanCallback.getBatchScanResults();
+        assertTrue(!results.isEmpty());
+        verifyTimestamp(results, scanStartMillis, scanEndMillis);
+    }
+
+    // Verify timestamp of all scan results are within [scanStartMillis, scanEndMillis].
+    private void verifyTimestamp(Collection<ScanResult> results, long scanStartMillis,
+            long scanEndMillis) {
+        for (ScanResult result : results) {
+            long timestampMillis = TimeUnit.NANOSECONDS.toMillis(result.getTimestampNanos());
+            assertTrue("Invalid timestamp", timestampMillis >= scanStartMillis);
+            assertTrue("Invalid timestamp", timestampMillis <= scanEndMillis);
+        }
+    }
+
+    // Helper class for BLE scan callback.
+    private class BleScanCallback extends ScanCallback {
+        private Set<ScanResult> mResults = new HashSet<ScanResult>();
+        private List<ScanResult> mBatchScanResults = new ArrayList<ScanResult>();
+
+        @Override
+        public void onScanResult(int callbackType, ScanResult result) {
+            if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
+                mResults.add(result);
+            }
+        }
+
+        @Override
+        public void onBatchScanResults(List<ScanResult> results) {
+            mBatchScanResults = results;
+        }
+
+        // Clear regular and batch scan results.
+        synchronized public void clear() {
+            mResults.clear();
+            mBatchScanResults.clear();
+        }
+
+        // Return regular BLE scan results accumulated so far.
+        synchronized Collection<ScanResult> getScanResults() {
+            return Collections.unmodifiableCollection(mResults);
+        }
+
+        // Return batch scan results.
+        synchronized List<ScanResult> getBatchScanResults() {
+            return Collections.unmodifiableList(mBatchScanResults);
+        }
+    }
+
+    // Put the current thread to sleep.
+    private void sleep(int sleepMillis) {
+        try {
+            Thread.sleep(sleepMillis);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "interrupted", e);
+        }
+    }
+
+}
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index 7c5dc50..c87a3e7 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -19,7 +19,6 @@
 import com.android.cts.content.R;
 import com.android.internal.util.XmlUtils;
 
-
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
@@ -30,6 +29,7 @@
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.WindowManager;
 
 import java.io.IOException;
 
@@ -155,6 +155,24 @@
         testTypedArray.recycle();
     }
 
+    public void testGetSystemService() {
+        // Test invalid service name
+        assertNull(mContext.getSystemService("invalid"));
+
+        // Test valid service name
+        assertNotNull(mContext.getSystemService(Context.WINDOW_SERVICE));
+    }
+
+    public void testGetSystemServiceByClass() {
+        // Test invalid service class
+        assertNull(mContext.getSystemService(Object.class));
+
+        // Test valid service name
+        assertNotNull(mContext.getSystemService(WindowManager.class));
+        assertEquals(mContext.getSystemService(Context.WINDOW_SERVICE),
+                mContext.getSystemService(WindowManager.class));
+    }
+
     private AttributeSet getAttributeSet(int resourceId) {
         final XmlResourceParser parser = getContext().getResources().getXml(
                 resourceId);
diff --git a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
index 62fc83a..672d3ed 100644
--- a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
@@ -18,7 +18,6 @@
 
 import com.android.cts.content.R;
 
-
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -44,6 +43,7 @@
 import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.test.AndroidTestCase;
+import android.view.WindowManager;
 
 import java.io.File;
 import java.io.IOException;
@@ -718,6 +718,16 @@
         assertNotNull(mContextWrapper.getSystemService(Context.WINDOW_SERVICE));
     }
 
+    public void testGetSystemServiceByClass() {
+        // Test invalid service class
+        assertNull(mContextWrapper.getSystemService(Object.class));
+
+        // Test valid service name
+        assertNotNull(mContextWrapper.getSystemService(WindowManager.class));
+        assertEquals(mContextWrapper.getSystemService(Context.WINDOW_SERVICE),
+                mContextWrapper.getSystemService(WindowManager.class));
+    }
+
     public void testGetAssets() {
         assertSame(mContext.getAssets(), mContextWrapper.getAssets());
     }
diff --git a/tests/tests/database/src/android/database/cts/AbstractCursorTest.java b/tests/tests/database/src/android/database/cts/AbstractCursorTest.java
index 078c2dd..c4371af 100644
--- a/tests/tests/database/src/android/database/cts/AbstractCursorTest.java
+++ b/tests/tests/database/src/android/database/cts/AbstractCursorTest.java
@@ -431,7 +431,6 @@
         public TestAbstractCursor(String[] columnNames, ArrayList<ArrayList> rows) {
             int colCount = columnNames.length;
             boolean foundID = false;
-            mRowIdColumnIndex = 0;
 
             // Add an _id column if not in columnNames
             for (int i = 0; i < colCount; ++i) {
diff --git a/tests/tests/deqp/Android.mk b/tests/tests/deqp/Android.mk
index d8a4dda..242cb39 100644
--- a/tests/tests/deqp/Android.mk
+++ b/tests/tests/deqp/Android.mk
@@ -24,3 +24,9 @@
 include $(LOCAL_PATH)/deqp_gles2.mk
 include $(LOCAL_PATH)/deqp_gles3.mk
 include $(LOCAL_PATH)/deqp_gles31.mk
+
+# Make the deqp app and copy it to CTS out dir.
+cts_deqp_name := com.drawelements.deqp
+cts_deqp_apk := $(CTS_TESTCASES_OUT)/$(cts_deqp_name).apk
+$(cts_deqp_apk): $(call intermediates-dir-for,APPS,$(cts_deqp_name))/package.apk
+	$(call copy-file-to-target)
diff --git a/tests/tests/display/Android.mk b/tests/tests/display/Android.mk
index a48a8e3..f17f580 100644
--- a/tests/tests/display/Android.mk
+++ b/tests/tests/display/Android.mk
@@ -29,7 +29,4 @@
 
 LOCAL_SDK_VERSION := current
 
-# This test runner sets up/cleans up the device before/after running the tests.
-LOCAL_CTS_TEST_RUNNER := com.android.cts.tradefed.testtype.DisplayTestRunner
-
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/display/AndroidTest.xml b/tests/tests/display/AndroidTest.xml
new file mode 100644
index 0000000..88d55bd
--- /dev/null
+++ b/tests/tests/display/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Base config for CTS package preparer">
+    <include name="common-config" />
+    <!-- Use a non-standard pattern, must match values in tests/tests/display/.../DisplayTest.java -->
+    <option name="run-command:run-command" value="settings put global overlay_display_devices 1281x721/214" />
+    <option name="run-command:teardown-command" value="settings put global overlay_display_devices &quot;&quot;" />
+</configuration>
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index 0006634..4249bb3 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -50,6 +50,7 @@
 
         <activity android:name="android.opengl.cts.OpenGlEsVersionCtsActivity"/>
 
+        <activity android:name="android.graphics.drawable.cts.DrawableStubActivity"/>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/graphics/res/anim/animation_grouping_1_01.xml b/tests/tests/graphics/res/anim/animation_grouping_1_01.xml
index 8cc9f92..c1f2904 100644
--- a/tests/tests/graphics/res/anim/animation_grouping_1_01.xml
+++ b/tests/tests/graphics/res/anim/animation_grouping_1_01.xml
@@ -18,9 +18,9 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <objectAnimator
-        android:duration="3300"
+        android:duration="50"
         android:propertyName="rotation"
         android:valueFrom="0"
         android:valueTo="180"
-        android:repeatCount="-1" />
+        android:repeatCount="2" />
 </set>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
new file mode 100644
index 0000000..f8b660a
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
new file mode 100644
index 0000000..e86e1b0
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
index aee8ff5..4141d6f 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
index e0e14f3..5308c7b 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
index b6798c2..e507b53 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
Binary files differ
diff --git a/apps/CtsVerifier/lib/colorchecker/vec3.cpp b/tests/tests/graphics/res/drawable/inset_mutate.xml
similarity index 70%
copy from apps/CtsVerifier/lib/colorchecker/vec3.cpp
copy to tests/tests/graphics/res/drawable/inset_mutate.xml
index ac16620..ba613e9 100644
--- a/apps/CtsVerifier/lib/colorchecker/vec3.cpp
+++ b/tests/tests/graphics/res/drawable/inset_mutate.xml
@@ -1,5 +1,6 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,11 +13,7 @@
  * 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.
- */
-#define LOG_NDEBUG 0
+ -->
 
-#define LOG_TAG "Vec3"
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#include "vec3.h"
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:drawable="@drawable/inset_mutate_testimage" />
diff --git a/tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg b/tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg
new file mode 100644
index 0000000..754df0c
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/vector_icon_clip_path_1.xml b/tests/tests/graphics/res/drawable/vector_icon_clip_path_1.xml
index c2ab429..53a9660 100644
--- a/tests/tests/graphics/res/drawable/vector_icon_clip_path_1.xml
+++ b/tests/tests/graphics/res/drawable/vector_icon_clip_path_1.xml
@@ -14,10 +14,10 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:height="64dp"
-        android:width="64dp"
-        android:viewportHeight="12.25"
-        android:viewportWidth="7.30625" >
+    android:height="64dp"
+    android:viewportHeight="12.25"
+    android:viewportWidth="7.30625"
+    android:width="64dp" >
 
     <group
         android:pivotX="3.65"
@@ -31,14 +31,18 @@
                 l 0, 12.25
                 l -7.3, 0
                 z" />
-    </group>
-    <group>
-        <path
-            android:name="one"
-            android:fillColor="#ff88ff"
-            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875 -2.109375,0.421875 0.0-1.078125
+
+        <group
+            android:pivotX="3.65"
+            android:pivotY="6.125"
+            android:rotation="30" >
+            <path
+                android:name="one"
+                android:fillColor="#ff88ff"
+                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875 -2.109375,0.421875 0.0-1.078125
                 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
                 l -5.046875,0.0 0.0-1.0Z" />
+        </group>
     </group>
     <group
         android:pivotX="3.65"
@@ -52,12 +56,15 @@
                 l 0, 6.125
                 l -7.3, 0
                 z" />
-    </group>
-    <group>
-        <path
-            android:name="two"
-            android:fillColor="#ff88ff"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+
+        <group
+            android:pivotX="3.65"
+            android:pivotY="6.125"
+            android:rotation="30" >
+            <path
+                android:name="two"
+                android:fillColor="#ff88ff"
+                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
                         q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
                         q 0.234375-0.453125 0.234375-0.875 0.0-0.703125 -0.5-1.140625
                         q -0.484375-0.4375 -1.2656252-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -66,6 +73,7 @@
                         q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
                         q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
                         q -0.78125024,0.8125 -2.2187502,2.265625Z" />
+        </group>
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_delete.xml b/tests/tests/graphics/res/drawable/vector_icon_delete.xml
index 8d9c21c..7b8f2aa 100644
--- a/tests/tests/graphics/res/drawable/vector_icon_delete.xml
+++ b/tests/tests/graphics/res/drawable/vector_icon_delete.xml
@@ -24,6 +24,6 @@
 
     <path
         android:fillColor="#FF000000"
-        android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0-0.896 2.0-2.0l0.0-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
+        android:pathData="M6.0,19.0c0.0,1.104 896e-3,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0-896e-3 2.0-2.0l0.0-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_heart.xml b/tests/tests/graphics/res/drawable/vector_icon_heart.xml
index ff55fe5..ad991c9 100644
--- a/tests/tests/graphics/res/drawable/vector_icon_heart.xml
+++ b/tests/tests/graphics/res/drawable/vector_icon_heart.xml
@@ -24,6 +24,6 @@
 
     <path
         android:fillColor="#FF000000"
-        android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
+        android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_scale_1.xml b/tests/tests/graphics/res/drawable/vector_icon_scale_1.xml
new file mode 100644
index 0000000..530c73b
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_scale_1.xml
@@ -0,0 +1,52 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="-1"
+        android:scaleY="-1" >
+        <group
+            android:scaleX="-1"
+            android:scaleY="-1" >
+            <group
+                android:pivotX="100"
+                android:pivotY="100"
+                android:rotation="45" >
+                <path
+                    android:name="twoLines"
+                    android:fillColor="#FFFF0000"
+                    android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                    android:strokeColor="#FF00FF00"
+                    android:strokeWidth="10" />
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_scale_2.xml b/tests/tests/graphics/res/drawable/vector_icon_scale_2.xml
new file mode 100644
index 0000000..200eb61
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_scale_2.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="2"
+        android:scaleY="0.5" >
+        <group
+            android:pivotX="100"
+            android:pivotY="100"
+            android:rotation="45" >
+            <path
+                android:name="twoLines"
+                android:fillColor="#FFFF0000"
+                android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="10" />
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
index 125a6b0..553d05d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
@@ -93,7 +93,6 @@
         // rounded corner must have less pixels than a sharp corner
         assertTrue(cornerPixels < 2 * RADIUS);
         // ... but not as few as a diagonal
-        // ToBeFixed: The following should be assertTrue (see bug 2037365)
-        assertFalse(cornerPixels > RADIUS);
+        assertTrue(cornerPixels > Math.sqrt(2 * Math.pow(RADIUS, 2)));
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index 1f709d3..a4a7bfd 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -19,6 +19,7 @@
 
 import android.graphics.ColorFilter;
 import android.graphics.MaskFilter;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Paint.Align;
 import android.graphics.Paint.Cap;
@@ -28,6 +29,8 @@
 import android.graphics.PathEffect;
 import android.graphics.Rasterizer;
 import android.graphics.Shader;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
 import android.graphics.Typeface;
 import android.graphics.Xfermode;
 import android.os.Build;
@@ -190,7 +193,7 @@
         assertEquals(m, p2.getMaskFilter());
         assertEquals(e, p2.getPathEffect());
         assertEquals(r, p2.getRasterizer());
-        assertNotSame(s, p2.getShader());
+        assertEquals(s, p2.getShader());
         assertEquals(t, p2.getTypeface());
         assertEquals(x, p2.getXfermode());
 
@@ -199,7 +202,7 @@
         assertEquals(m, p2.getMaskFilter());
         assertEquals(e, p2.getPathEffect());
         assertEquals(r, p2.getRasterizer());
-        assertNotSame(s, p2.getShader());
+        assertEquals(s, p2.getShader());
         assertEquals(t, p2.getTypeface());
         assertEquals(x, p2.getXfermode());
 
@@ -271,6 +274,35 @@
         assertNull(p.getShader());
     }
 
+    public void testShaderLocalMatrix() {
+        int width = 80;
+        int height = 120;
+        int[] color = new int[width * height];
+        Bitmap bitmap = Bitmap.createBitmap(color, width, height, Bitmap.Config.RGB_565);
+
+        Paint p = new Paint();
+        Matrix m = new Matrix();
+        Shader s = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
+
+        // set the shaders matrix to a non identity value and attach to paint
+        m.setScale(10, 0);
+        s.setLocalMatrix(m);
+        p.setShader(s);
+
+        Matrix m2 = new Matrix();
+        assertTrue(p.getShader().getLocalMatrix(m2));
+        assertEquals(m, m2);
+
+        // updated the matrix again and set it on the shader but NOT the paint
+        m.setScale(0, 10);
+        s.setLocalMatrix(m);
+
+        // assert that the matrix on the paint's shader also changed
+        Matrix m3 = new Matrix();
+        assertTrue(p.getShader().getLocalMatrix(m3));
+        assertEquals(m, m3);
+    }
+
     public void testSetAntiAlias() {
         Paint p = new Paint();
 
@@ -1001,4 +1033,35 @@
         }
     }
 
+    public void testHasGlyph() {
+        Paint p = new Paint();
+
+        // This method tests both the logic of hasGlyph and the sanity of fonts present
+        // on the device.
+        assertTrue(p.hasGlyph("A"));
+        assertFalse(p.hasGlyph("\uFFFE"));  // U+FFFE is guaranteed to be a noncharacter
+
+        // Roboto 2 (the default typeface) does have an "fi" glyph and is mandated by CDD
+        assertTrue(p.hasGlyph("fi"));
+        assertFalse(p.hasGlyph("ab"));  // but it does not contain an "ab" glyph
+        assertTrue(p.hasGlyph("\u02E5\u02E9"));  // IPA tone mark ligature
+
+        // variation selectors
+        assertFalse(p.hasGlyph("a\uFE0F"));
+        assertFalse(p.hasGlyph("a\uDB40\uDDEF"));  // UTF-16 encoding of U+E01EF
+        assertFalse(p.hasGlyph("\u2229\uFE0F"));  // base character is in mathematical symbol font
+        // Note: U+FE0F is variation selection, unofficially reserved for emoji
+
+        // regional indicator symbols
+        assertTrue(p.hasGlyph("\uD83C\uDDEF\uD83C\uDDF5"));   // "JP" U+1F1EF U+1F1F5
+        assertFalse(p.hasGlyph("\uD83C\uDDFF\uD83C\uDDFF"));  // "ZZ" U+1F1FF U+1F1FF
+
+        // Mongolian, which is an optional font, but if present, should support FVS
+        if (p.hasGlyph("\u182D")) {
+            assertTrue(p.hasGlyph("\u182D\u180B"));
+        }
+
+        // TODO: when we support variation selectors, add positive tests
+    }
+
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
index b4c64e2..b572dcf 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -16,12 +16,14 @@
 
 package android.graphics.drawable.cts;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable.ConstantState;
-import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -35,12 +37,13 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-public class AnimatedVectorDrawableTest extends AndroidTestCase {
+public class AnimatedVectorDrawableTest extends ActivityInstrumentationTestCase2<DrawableStubActivity> {
     private static final String LOGTAG = AnimatedVectorDrawableTest.class.getSimpleName();
 
     private static final int IMAGE_WIDTH = 64;
     private static final int IMAGE_HEIGHT = 64;
 
+    private DrawableStubActivity mActivity;
     private Resources mResources;
     private AnimatedVectorDrawable mAnimatedVectorDrawable;
     private Bitmap mBitmap;
@@ -48,6 +51,10 @@
     private static final boolean DBG_DUMP_PNG = false;
     private int mResId = R.drawable.animation_vector_drawable_grouping_1;
 
+    public AnimatedVectorDrawableTest() {
+        super(DrawableStubActivity.class);
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -56,7 +63,8 @@
         mCanvas = new Canvas(mBitmap);
         mAnimatedVectorDrawable = new AnimatedVectorDrawable();
 
-        mResources = mContext.getResources();
+        mActivity = getActivity();
+        mResources = mActivity.getResources();
     }
 
     // This is only for debugging or golden image (re)generation purpose.
@@ -156,11 +164,9 @@
     }
 
     public void testMutate() {
-        Resources resources = mContext.getResources();
-
-        AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) resources.getDrawable(mResId);
-        AnimatedVectorDrawable d2 = (AnimatedVectorDrawable) resources.getDrawable(mResId);
-        AnimatedVectorDrawable d3 = (AnimatedVectorDrawable) resources.getDrawable(mResId);
+        AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
+        AnimatedVectorDrawable d2 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
+        AnimatedVectorDrawable d3 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
         int originalAlpha = d2.getAlpha();
         int newAlpha = (originalAlpha + 1) % 255;
 
@@ -183,4 +189,64 @@
         assertEquals(0x20, d2.getAlpha());
         assertEquals(originalAlpha, d3.getAlpha());
     }
+
+    public void testAddRemoveListener() {
+        AnimatorListenerAdapter listener1 = new AnimatorListenerAdapter() {};
+        AnimatorListenerAdapter listener2 = new AnimatorListenerAdapter() {};
+        AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
+
+        d1.addListener(listener1);
+        d1.addListener(listener2);
+
+        assertTrue(d1.getListeners().contains(listener1));
+        assertTrue(d1.getListeners().contains(listener2));
+
+        d1.removeListener(listener1);
+        assertFalse(d1.getListeners().contains(listener1));
+
+        d1.removeListener(listener2);
+        assertTrue(d1.getListeners() == null);
+    }
+
+    public void testListener() throws InterruptedException {
+        MyListener listener = new MyListener();
+        final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
+
+        d1.addListener(listener);
+        // The AVD has a duration as 100ms.
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                d1.start();
+            }
+        });
+
+        Thread.sleep(200);
+
+        assertTrue(listener.mStart);
+        assertTrue(listener.mEnd);
+        assertFalse(listener.mCancel);
+    }
+
+    class MyListener implements Animator.AnimatorListener{
+        boolean mStart = false;
+        boolean mEnd = false;
+        boolean mCancel = false;
+        int mRepeat = 0;
+
+        public void onAnimationCancel(Animator animation) {
+            mCancel = true;
+        }
+
+        public void onAnimationEnd(Animator animation) {
+            mEnd = true;
+        }
+
+        public void onAnimationRepeat(Animator animation) {
+            mRepeat++;
+        }
+
+        public void onAnimationStart(Animator animation) {
+            mStart = true;
+        }
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
index 7e3294d..da96cdc 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
@@ -22,6 +22,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -232,16 +233,24 @@
     }
 
     public void testOnStateChange() {
-        MockDrawable mockDrawable = new MockDrawable();
-        MockClipDrawable mockClipDrawable = new MockClipDrawable(mockDrawable,
+        Drawable d = mContext.getDrawable(R.drawable.pass);
+        MockClipDrawable clipDrawable = new MockClipDrawable(d,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
-        assertEquals(StateSet.WILD_CARD, mockDrawable.getState());
+        assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
 
-        int[] states = new int[] {1, 2, 3};
-        assertFalse(mockClipDrawable.onStateChange(states));
-        assertEquals(states, mockDrawable.getState());
+        int[] state = new int[] {1, 2, 3};
+        assertFalse("child did not change", clipDrawable.onStateChange(state));
+        assertEquals("child state did not change", d.getState(), StateSet.WILD_CARD);
 
-        mockClipDrawable.onStateChange(null);
+        d = mContext.getDrawable(R.drawable.statelistdrawable);
+        clipDrawable = new MockClipDrawable(d, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
+        assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
+        clipDrawable.onStateChange(state);
+        assertTrue("child state changed", Arrays.equals(state, d.getState()));
+
+        // input null as param
+        clipDrawable.onStateChange(null);
+        // expected, no Exception thrown out, test success
     }
 
     public void testScheduleDrawable() {
diff --git a/apps/CtsVerifier/lib/colorchecker/vec3.cpp b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableStubActivity.java
similarity index 75%
rename from apps/CtsVerifier/lib/colorchecker/vec3.cpp
rename to tests/tests/graphics/src/android/graphics/drawable/cts/DrawableStubActivity.java
index ac16620..a7b27b3 100644
--- a/apps/CtsVerifier/lib/colorchecker/vec3.cpp
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableStubActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_NDEBUG 0
+package android.graphics.drawable.cts;
 
-#define LOG_TAG "Vec3"
-#include <utils/Log.h>
-#include <utils/Timers.h>
+import android.app.Activity;
 
-#include "vec3.h"
+public class DrawableStubActivity extends Activity {
+}
+
+
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
index 1edd36e..9c5f063 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
@@ -18,7 +18,6 @@
 
 import com.android.cts.graphics.R;
 
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -32,13 +31,16 @@
 import android.graphics.drawable.Drawable.ConstantState;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
+import android.util.StateSet;
 import android.util.Xml;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 public class InsetDrawableTest extends AndroidTestCase {
+
     public void testConstructor() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         new InsetDrawable(d, 1);
         new InsetDrawable(d, 1, 1, 1, 1);
 
@@ -47,8 +49,7 @@
     }
 
     public void testInflate() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
+        InsetDrawable insetDrawable = new InsetDrawable(null, 0);
 
         Resources r = mContext.getResources();
         XmlPullParser parser = r.getXml(R.layout.framelayout_layout);
@@ -77,14 +78,14 @@
     }
 
     public void testInvalidateDrawable() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         insetDrawable.invalidateDrawable(d);
     }
 
     public void testScheduleDrawable() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         Runnable runnable = new Runnable() {
@@ -99,7 +100,7 @@
     }
 
     public void testUnscheduleDrawable() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         Runnable runnable = new Runnable() {
@@ -114,7 +115,7 @@
     }
 
     public void testDraw() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         Canvas c = new Canvas();
@@ -130,7 +131,7 @@
     }
 
     public void testGetChangingConfigurations() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         insetDrawable.setChangingConfigurations(11);
@@ -141,7 +142,7 @@
     }
 
     public void testGetPadding() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 1, 2, 3, 4);
 
         Rect r = new Rect();
@@ -183,7 +184,7 @@
     }
 
     public void testSetVisible() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         assertFalse(insetDrawable.setVisible(true, true)); /* unchanged */
@@ -192,7 +193,7 @@
     }
 
     public void testSetAlpha() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         insetDrawable.setAlpha(1);
@@ -204,7 +205,7 @@
     }
 
     public void testSetColorFilter() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         ColorFilter cf = new ColorFilter();
@@ -216,7 +217,7 @@
     }
 
     public void testGetOpacity() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.testimage);
+        Drawable d = mContext.getDrawable(R.drawable.testimage);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
         insetDrawable.setAlpha(255);
         assertEquals(PixelFormat.OPAQUE, insetDrawable.getOpacity());
@@ -226,28 +227,25 @@
     }
 
     public void testIsStateful() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
         assertFalse(insetDrawable.isStateful());
     }
 
     public void testOnStateChange() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         MockInsetDrawable insetDrawable = new MockInsetDrawable(d, 10);
-
-        Rect bounds = d.getBounds();
-        assertEquals(0, bounds.left);
-        assertEquals(0, bounds.top);
-        assertEquals(0, bounds.right);
-        assertEquals(0, bounds.bottom);
+        assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
 
         int[] state = new int[] {1, 2, 3};
-        assertFalse(insetDrawable.onStateChange(state));
+        assertFalse("child did not change", insetDrawable.onStateChange(state));
+        assertEquals("child state did not change", d.getState(), StateSet.WILD_CARD);
 
-        assertEquals(10, bounds.left);
-        assertEquals(10, bounds.top);
-        assertEquals(-10, bounds.right);
-        assertEquals(-10, bounds.bottom);
+        d = mContext.getDrawable(R.drawable.statelistdrawable);
+        insetDrawable = new MockInsetDrawable(d, 10);
+        assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
+        insetDrawable.onStateChange(state);
+        assertTrue("child state changed", Arrays.equals(state, d.getState()));
 
         // input null as param
         insetDrawable.onStateChange(null);
@@ -255,7 +253,7 @@
     }
 
     public void testOnBoundsChange() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         MockInsetDrawable insetDrawable = new MockInsetDrawable(d, 5);
 
         Rect bounds = d.getBounds();
@@ -282,13 +280,13 @@
     }
 
     public void testGetIntrinsicWidth() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         int expected = d.getIntrinsicWidth(); /* 31 */
         assertEquals(expected, insetDrawable.getIntrinsicWidth());
 
-        d = mContext.getResources().getDrawable(R.drawable.scenery);
+        d = mContext.getDrawable(R.drawable.scenery);
         insetDrawable = new InsetDrawable(d, 0);
 
         expected = d.getIntrinsicWidth(); /* 170 */
@@ -296,13 +294,13 @@
     }
 
     public void testGetIntrinsicHeight() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         int expected = d.getIntrinsicHeight(); /* 31 */
         assertEquals(expected, insetDrawable.getIntrinsicHeight());
 
-        d = mContext.getResources().getDrawable(R.drawable.scenery);
+        d = mContext.getDrawable(R.drawable.scenery);
         insetDrawable = new InsetDrawable(d, 0);
 
         expected = d.getIntrinsicHeight(); /* 107 */
@@ -310,13 +308,31 @@
     }
 
     public void testGetConstantState() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
         ConstantState constantState = insetDrawable.getConstantState();
         assertNotNull(constantState);
     }
 
+    public void testMutate() {
+        // Obtain the first instance, then mutate and modify a property held by
+        // constant state. If mutate() works correctly, the property should not
+        // be modified on the second or third instances.
+        Resources res = mContext.getResources();
+        InsetDrawable first = (InsetDrawable) res.getDrawable(R.drawable.inset_mutate, null);
+        InsetDrawable pre = (InsetDrawable) res.getDrawable(R.drawable.inset_mutate, null);
+
+        first.mutate().setAlpha(128);
+
+        assertEquals("Modified first loaded instance", 128, first.getDrawable().getAlpha());
+        assertEquals("Did not modify pre-mutate() instance", 255, pre.getDrawable().getAlpha());
+
+        InsetDrawable post = (InsetDrawable) res.getDrawable(R.drawable.inset_mutate, null);
+
+        assertEquals("Did not modify post-mutate() instance", 255, post.getDrawable().getAlpha());
+    }
+
     private class MockInsetDrawable extends InsetDrawable {
         public MockInsetDrawable(Drawable drawable, int inset) {
             super(drawable, inset);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index 5aa3083..c9ee330 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -39,12 +39,14 @@
 import android.graphics.drawable.RotateDrawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.StateListDrawable;
+import android.os.Debug;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.view.View;
 
 public class LayerDrawableTest extends AndroidTestCase {
+
     @SuppressWarnings("deprecation")
     public void testConstructor() {
         Drawable bitmapDrawable = new BitmapDrawable();
@@ -60,9 +62,9 @@
         assertEquals(0, layerDrawable.getNumberOfLayers());
 
         try {
-            new LayerDrawable((Drawable[]) null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
+            new LayerDrawable(null);
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
         }
     }
 
@@ -77,7 +79,7 @@
 
         assertEquals(4, layerDrawable.getNumberOfLayers());
         assertEquals(ColorDrawable.class, layerDrawable.getDrawable(0).getClass());
-        assertEquals(0x88, (((ColorDrawable) layerDrawable.getDrawable(0)).getAlpha()));
+        assertEquals(0x88, layerDrawable.getDrawable(0).getAlpha());
         assertEquals(View.NO_ID, layerDrawable.getId(0));
         assertEquals(BitmapDrawable.class, layerDrawable.getDrawable(1).getClass());
         assertEquals(View.NO_ID, layerDrawable.getId(1));
@@ -556,70 +558,85 @@
         assertTrue(layerDrawable.isStateful());
     }
 
-    public void testOnStateChange() {
+    public void testSetState() {
         MockDrawable mockDrawable1 = new MockDrawable(true);
         MockDrawable mockDrawable2 = new MockDrawable(true);
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
-        MockLayerDrawable layerDrawable = new MockLayerDrawable(array);
+        LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        // this method will call each child's setState().
-        assertFalse(layerDrawable.onStateChange(StateSet.WILD_CARD));
-        assertTrue(mockDrawable1.hasCalledSetState());
-        assertTrue(mockDrawable2.hasCalledSetState());
-        assertTrue(layerDrawable.hasCalledOnBoundsChange());
+        // Call onStateChange() without actually changing the state.
+        assertFalse(layerDrawable.setState(StateSet.WILD_CARD));
+        assertFalse(mockDrawable1.hasCalledSetState());
+        assertFalse(mockDrawable2.hasCalledSetState());
+        assertFalse(mockDrawable1.hasCalledOnBoundsChange());
+        assertFalse(mockDrawable2.hasCalledOnBoundsChange());
 
+        // Call onStateChange() to change the state from WILD_CARD to null.
+        // This alters the padding of both layers, which forces a bounds change
+        // for the second layer due to the default "nest" padding mode.
         mockDrawable1.reset();
         mockDrawable2.reset();
-        layerDrawable.reset();
-        assertTrue(layerDrawable.onStateChange(null));
+        assertTrue(layerDrawable.setState(null));
         assertTrue(mockDrawable1.hasCalledSetState());
         assertTrue(mockDrawable2.hasCalledSetState());
-        assertTrue(layerDrawable.hasCalledOnBoundsChange());
+        assertFalse(mockDrawable1.hasCalledOnBoundsChange());
+        assertTrue(mockDrawable2.hasCalledOnBoundsChange());
 
+        // Call onStateChange() to change the state from null to valid state
+        // set. This alters the padding of both layers, which forces a bounds
+        // change for the second layer due to the default "nest" padding mode.
         mockDrawable1.reset();
         mockDrawable2.reset();
-        layerDrawable.reset();
-        assertTrue(layerDrawable.onStateChange(new int[] { attr.state_checked, attr.state_empty }));
+        assertTrue(layerDrawable.setState(new int[]{
+                android.R.attr.state_checked, android.R.attr.state_empty}));
         assertTrue(mockDrawable1.hasCalledSetState());
         assertTrue(mockDrawable2.hasCalledSetState());
-        assertTrue(layerDrawable.hasCalledOnBoundsChange());
+        assertFalse(mockDrawable1.hasCalledOnBoundsChange());
+        assertTrue(mockDrawable2.hasCalledOnBoundsChange());
     }
 
-    public void testOnLevelChange() {
+    public void testSetLevel() {
         MockDrawable mockDrawable1 = new MockDrawable();
         MockDrawable mockDrawable2 = new MockDrawable();
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
-        MockLayerDrawable layerDrawable = new MockLayerDrawable(array);
+        LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        // this method will call each child's setLevel(),
-        // but just when set a different level the child's onLevelChange will be called.
-        assertFalse(layerDrawable.onLevelChange(0));
+        // Call onLevelChange() without actually changing the level.
+        assertFalse(layerDrawable.setLevel(0));
         assertFalse(mockDrawable1.hasCalledOnLevelChange());
         assertFalse(mockDrawable2.hasCalledOnLevelChange());
-        assertFalse(layerDrawable.hasCalledOnBoundsChange());
+        assertFalse(mockDrawable1.hasCalledOnBoundsChange());
+        assertFalse(mockDrawable2.hasCalledOnBoundsChange());
 
+        // Call onLevelChange() to change the level from 0 to MAX_VALUE. This
+        // alters the padding of both layers, which forces a bounds change for
+        // the second layer due to the default "nest" padding mode.
         mockDrawable1.reset();
         mockDrawable2.reset();
-        layerDrawable.reset();
-        assertTrue(layerDrawable.onLevelChange(Integer.MAX_VALUE));
+        assertTrue(layerDrawable.setLevel(Integer.MAX_VALUE));
         assertTrue(mockDrawable1.hasCalledOnLevelChange());
         assertTrue(mockDrawable2.hasCalledOnLevelChange());
-        assertTrue(layerDrawable.hasCalledOnBoundsChange());
+        assertFalse(mockDrawable1.hasCalledOnBoundsChange());
+        assertTrue(mockDrawable2.hasCalledOnBoundsChange());
 
+        // Call onLevelChange() to change the level from MAX_VALUE to
+        // MIN_VALUE. This alters the padding of both layers, which forces a
+        // bounds change for the second layer due to the default "nest" padding
+        // mode.
         mockDrawable1.reset();
         mockDrawable2.reset();
-        layerDrawable.reset();
-        assertTrue(layerDrawable.onLevelChange(Integer.MIN_VALUE));
+        assertTrue(layerDrawable.setLevel(Integer.MIN_VALUE));
         assertTrue(mockDrawable1.hasCalledOnLevelChange());
         assertTrue(mockDrawable2.hasCalledOnLevelChange());
-        assertTrue(layerDrawable.hasCalledOnBoundsChange());
+        assertFalse(mockDrawable1.hasCalledOnBoundsChange());
+        assertTrue(mockDrawable2.hasCalledOnBoundsChange());
     }
 
-    public void testOnBoundsChange() {
+    public void testSetBounds() {
         MockDrawable mockDrawable1 = new MockDrawable();
         MockDrawable mockDrawable2 = new MockDrawable();
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
-        MockLayerDrawable layerDrawable = new MockLayerDrawable(array);
+        LayerDrawable layerDrawable = new LayerDrawable(array);
 
         Rect inset1 = new Rect(1, 2, 3, 4);
         Rect inset2 = new Rect(2, 4, 6, 7);
@@ -642,7 +659,7 @@
         assertEquals(0, mockDrawable2.getBounds().bottom);
 
         Rect bounds = new Rect(10, 20, 30, 40);
-        layerDrawable.onBoundsChange(bounds);
+        layerDrawable.setBounds(bounds);
 
         // all children's bounds will be changed after call onBoundsChange
         assertEquals(bounds.left + inset1.left, mockDrawable1.getBounds().left);
@@ -661,7 +678,7 @@
         MockDrawable mockDrawable1 = new MockDrawable();
         MockDrawable mockDrawable2 = new MockDrawable();
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
-        MockLayerDrawable layerDrawable = new MockLayerDrawable(array);
+        LayerDrawable layerDrawable = new LayerDrawable(array);
         assertEquals(mockDrawable1.getIntrinsicWidth(), layerDrawable.getIntrinsicWidth());
 
         Rect inset1 = new Rect(1, 2, 3, 4);
@@ -688,7 +705,7 @@
         MockDrawable mockDrawable1 = new MockDrawable();
         MockDrawable mockDrawable2 = new MockDrawable();
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
-        MockLayerDrawable layerDrawable = new MockLayerDrawable(array);
+        LayerDrawable layerDrawable = new LayerDrawable(array);
         assertEquals(mockDrawable1.getIntrinsicHeight(), layerDrawable.getIntrinsicHeight());
 
         Rect inset1 = new Rect(1, 2, 3, 4);
@@ -732,6 +749,8 @@
 
         private boolean mCalledSetState = false;
         private boolean mCalledOnLevelChange = false;
+        private boolean mCalledOnBoundsChange = false;
+
 
         private boolean mCalledDraw = false;
 
@@ -801,13 +820,15 @@
 
             mCalledSetState = false;
             mCalledOnLevelChange = false;
+            mCalledOnBoundsChange = false;
 
             mCalledDraw = false;
         }
 
         @Override
         protected boolean onStateChange(int[] state) {
-            return true;
+            increasePadding();
+            return mIsStateful;
         }
 
         private void increasePadding() {
@@ -829,6 +850,16 @@
         }
 
         @Override
+        protected void onBoundsChange(Rect bounds) {
+            mCalledOnBoundsChange = true;
+            super.onBoundsChange(bounds);
+        }
+
+        public boolean hasCalledOnBoundsChange() {
+            return mCalledOnBoundsChange;
+        }
+
+        @Override
         public boolean isStateful() {
             return mIsStateful;
         }
@@ -839,7 +870,6 @@
 
         @Override
         public boolean setState(final int[] stateSet) {
-            increasePadding();
             mCalledSetState = true;
             return super.setState(stateSet);
         }
@@ -870,44 +900,10 @@
         }
     }
 
-    private static class MockLayerDrawable extends LayerDrawable {
-        private boolean mCalledOnBoundsChange = false;
-
-        public MockLayerDrawable(Drawable[] array) {
-            super(array);
-        }
-
-        // override protected methods
-        @Override
-        protected boolean onStateChange(int[] state) {
-            return super.onStateChange(state);
-        }
-
-        @Override
-        protected boolean onLevelChange(int level) {
-            return super.onLevelChange(level);
-        }
-
-        @Override
-        protected void onBoundsChange(Rect bounds) {
-            mCalledOnBoundsChange = true;
-            super.onBoundsChange(bounds);
-        }
-
-        public boolean hasCalledOnBoundsChange() {
-            return mCalledOnBoundsChange;
-        }
-
-        public void reset() {
-            mCalledOnBoundsChange = false;
-        }
-    }
-
     public void testMutate() {
-        Resources resources = mContext.getResources();
-        LayerDrawable d1 = (LayerDrawable) resources.getDrawable(R.drawable.layerdrawable);
-        LayerDrawable d2 = (LayerDrawable) resources.getDrawable(R.drawable.layerdrawable);
-        LayerDrawable d3 = (LayerDrawable) resources.getDrawable(R.drawable.layerdrawable);
+        LayerDrawable d1 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
+        LayerDrawable d2 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
+        LayerDrawable d3 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
 
         d1.setAlpha(100);
         assertEquals(100, ((BitmapDrawable) d1.getDrawable(0)).getPaint().getAlpha());
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
index 6281582..3d758fe 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
@@ -259,7 +259,8 @@
         MockDrawable mockDrawable = new MockDrawable();
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
-        // this method will call contained drawable's getOpacity method.
+        // This method will call contained drawable's getOpacity method.
+        scaleDrawable.setLevel(1);
         scaleDrawable.getOpacity();
         assertTrue(mockDrawable.hasCalledGetOpacity());
     }
@@ -437,10 +438,9 @@
     }
 
     public void testMutate() {
-        Resources resources = mContext.getResources();
-        ScaleDrawable d1 = (ScaleDrawable) resources.getDrawable(R.drawable.scaledrawable);
-        ScaleDrawable d2 = (ScaleDrawable) resources.getDrawable(R.drawable.scaledrawable);
-        ScaleDrawable d3 = (ScaleDrawable) resources.getDrawable(R.drawable.scaledrawable);
+        ScaleDrawable d1 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable);
+        ScaleDrawable d2 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable);
+        ScaleDrawable d3 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable);
 
         d1.setAlpha(100);
         assertEquals(100, ((BitmapDrawable) d1.getDrawable()).getPaint().getAlpha());
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 8cee91e..a967f95 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
@@ -17,8 +17,6 @@
 package android.graphics.drawable.cts;
 
 import android.annotation.TargetApi;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.Shader.TileMode;
@@ -29,13 +27,11 @@
 import android.graphics.drawable.NinePatchDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.test.AndroidTestCase;
-import android.util.SparseIntArray;
-import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 
 import com.android.cts.graphics.R;
 
-@TargetApi(19)
+@TargetApi(21)
 public class ThemedDrawableTest extends AndroidTestCase {
 
     @Override
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
index 3578d3c..d266efd 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -63,6 +63,8 @@
             R.drawable.vector_icon_stroke_1,
             R.drawable.vector_icon_stroke_2,
             R.drawable.vector_icon_stroke_3,
+            R.drawable.vector_icon_scale_1,
+            R.drawable.vector_icon_scale_2,
     };
 
     private int[] mGoldenImages = new int[] {
@@ -89,6 +91,8 @@
             R.drawable.vector_icon_stroke_1_golden,
             R.drawable.vector_icon_stroke_2_golden,
             R.drawable.vector_icon_stroke_3_golden,
+            R.drawable.vector_icon_scale_1_golden,
+            R.drawable.vector_icon_scale_2_golden,
     };
 
     private static final int IMAGE_WIDTH = 64;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
new file mode 100644
index 0000000..a64ceb9
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
@@ -0,0 +1,721 @@
+/*
+ * 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 android.hardware.camera2.cts;
+
+import static android.hardware.camera2.cts.CameraTestUtils.*;
+
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureRequest.Builder;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
+import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
+import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.util.Log;
+import android.util.Range;
+import android.util.Size;
+
+import java.util.ArrayList;
+
+/**
+ * Basic tests for burst capture in RAW10/16.
+ */
+public class BurstCaptureRawTest extends Camera2SurfaceViewTestCase {
+    private static final String TAG = "BurstCaptureRawTest";
+    private static final int RAW_FORMATS[] = {
+            ImageFormat.RAW10, ImageFormat.RAW_SENSOR };
+    private static final long EXPOSURE_MULTIPLIERS[] = {
+            1, 3, 5 };
+    private static final int SENSITIVITY_MLTIPLIERS[] = {
+            1, 3, 5 };
+    private static final int MAX_FRAMES_BURST =
+            EXPOSURE_MULTIPLIERS.length * SENSITIVITY_MLTIPLIERS.length;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Verify raw sensor size information is correctly configured.
+     */
+    public void testRawSensorSize() throws Exception {
+        Log.i(TAG, "Begin testRawSensorSize");
+        for (String id : mCameraIds) {
+            try {
+                openDevice(id);
+
+                ArrayList<Integer> supportedRawList = new ArrayList<Integer>(RAW_FORMATS.length);
+                if (!checkCapability(supportedRawList)) {
+                    Log.i(TAG, "Capability is not supported on camera " + id
+                            + ". Skip the test.");
+                    continue;
+                }
+
+                Size[] rawSizes = mStaticInfo.getRawOutputSizesChecked();
+                assertTrue("No capture sizes available for RAW format!", rawSizes.length != 0);
+
+                Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
+                Size size = new Size(activeArray.width(), activeArray.height());
+                mCollector.expectTrue("Missing ActiveArraySize",
+                        activeArray.width() > 0 && activeArray.height() > 0);
+                mCollector.expectContains(
+                        "Available sizes for RAW format must include ActiveArraySize",
+                        rawSizes, size);
+
+            } finally {
+                closeDevice();
+            }
+        }
+        Log.i(TAG, "End testRawSensorSize");
+    }
+
+    /**
+     * Round [exposure, gain] down, rather than to the nearest, in RAW 10/16
+     * <p>
+     * Verify the value of metadata (exposure and sensitivity) is rounded down if the request cannot
+     * be honored.
+     * </p>
+     */
+    public void testMetadataRoundDown() throws Exception {
+        Log.i(TAG, "Begin testMetadataRoundDown");
+
+        performTestRoutine(new TestMetaDataRoundDownRoutine());
+
+        Log.i(TAG, "End testMetadataRoundDown");
+    }
+
+    /**
+     * Manual and Auto setting test in RAW10/16
+     * <p>
+     * Make sure switching between manual and auto setting would not make the capture results out of
+     * sync.
+     * </p>
+     */
+    public void testManualAutoSwitch() throws Exception {
+        Log.i(TAG, "Begin testManualAutoSwitch");
+
+        performTestRoutine(new TestManualAutoSwitch());
+
+        Log.i(TAG, "End testManualAutoSwitch");
+    }
+
+    /**
+     * Per frame timestamp test in RAW10/16
+     */
+    public void testTimestamp() throws Exception {
+        Log.i(TAG, "Begin testTimestamp");
+
+        performTestRoutine(new TestTimestamp());
+
+        Log.i(TAG, "End testTimestamp");
+    }
+
+    /*
+     * Below are private infrastructure for all tests
+     */
+
+    /**
+     * A structure encapsulates all the parameters for setting up preview, and RAW capture.
+     */
+    class CaptureSetup
+    {
+        public CaptureSetup(Size previewCaptureSize, Size rawCaptureSize,
+                CaptureRequest.Builder previewRequestBuilder,
+                CaptureRequest.Builder rawRequestBuilder,
+                SimpleCaptureCallback previewCaptureCallback,
+                SimpleCaptureCallback rawCaptureCallback,
+                SimpleImageReaderListener rawReaderListener)
+        {
+            mPreviewCaptureSize = previewCaptureSize;
+            mRawCaptureSize = rawCaptureSize;
+            mPreviewRequestBuilder = previewRequestBuilder;
+            mRawRequestBuilder = rawRequestBuilder;
+            mPreviewCaptureCallback = previewCaptureCallback;
+            mRawCaptureCallback = rawCaptureCallback;
+            mRawReaderListener = rawReaderListener;
+        }
+
+        public Size getPreviewCaptureSize()
+        {
+            return mPreviewCaptureSize;
+        }
+
+        public Size getRawCaptureSize()
+        {
+            return mRawCaptureSize;
+        }
+
+        public CaptureRequest.Builder getPreviewRequestBuilder()
+        {
+            return mPreviewRequestBuilder;
+        }
+
+        public CaptureRequest.Builder getRawRequestBuilder() {
+            return mRawRequestBuilder;
+        }
+
+        public SimpleCaptureCallback getPreviewCaptureCallback() {
+            return mPreviewCaptureCallback;
+        }
+
+        public SimpleCaptureCallback getRawCaptureCallback() {
+            return mRawCaptureCallback;
+        }
+
+        public SimpleImageReaderListener getRawReaderListener() {
+            return mRawReaderListener;
+        }
+
+        private Size mPreviewCaptureSize;
+        private Size mRawCaptureSize;
+        private CaptureRequest.Builder mPreviewRequestBuilder;
+        private CaptureRequest.Builder mRawRequestBuilder;
+
+        /** all the non-testing requests are sent to here */
+        private SimpleCaptureCallback mPreviewCaptureCallback;
+        /** all the testing requests are sent to here */
+        private SimpleCaptureCallback mRawCaptureCallback;
+        /** all the testing framebuffers are sent to here */
+        private SimpleImageReaderListener mRawReaderListener;
+    }
+
+    /**
+     * Interface for the test routines that are being called by performTestRoutines(). Implement
+     * different test cases in execute().
+     */
+    interface TestRoutine {
+        public void execute(CaptureRequest.Builder rawBurstBuilder,
+                SimpleCaptureCallback rawCaptureCallback,
+                SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception;
+    }
+
+    /**
+     * Implementation of metadata round down test.
+     */
+    class TestMetaDataRoundDownRoutine implements TestRoutine
+    {
+        @Override
+        public void execute(CaptureRequest.Builder rawBurstBuilder,
+                SimpleCaptureCallback rawCaptureCallback,
+                SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception
+        {
+            // build burst capture
+            ArrayList<CaptureRequest> rawRequestList = createBurstRequest(rawBurstBuilder);
+
+            // submit captrue
+            Log.i(TAG, "Submitting Burst Request.");
+            mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler);
+
+            // verify metadata
+            for (int i = 0; i < MAX_FRAMES_BURST; i++) {
+                CaptureResult result = rawCaptureCallback.getCaptureResult(
+                        CAPTURE_IMAGE_TIMEOUT_MS);
+
+                long resultExposure = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
+                int resultSensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY);
+                long desiredExposure = rawRequestList.get(i).get(
+                        CaptureRequest.SENSOR_EXPOSURE_TIME);
+                int desiredSensitivity = rawRequestList.get(i).get(
+                        CaptureRequest.SENSOR_SENSITIVITY);
+
+                Log.i(TAG, String.format(
+                        "Received capture result, exposure = %d, sensitivity = %d. "
+                                + "Requested exposure = %d, sensitivity = %d.",
+                        resultExposure,
+                        resultSensitivity, desiredExposure, desiredSensitivity));
+
+                mCollector.expectTrue(
+                        String.format("Exposure value is greater than requested: "
+                                + "requested = %d, result = %d.",
+                                desiredExposure, resultExposure),
+                                resultExposure <= desiredExposure);
+
+                mCollector.expectTrue(
+                        String.format("Sensitivity value is greater than requested: "
+                                + "requested = %d, result = %d.",
+                                desiredSensitivity, resultSensitivity),
+                                resultSensitivity <= desiredSensitivity);
+            }
+        }
+    }
+
+    /**
+     * Implementation of manual-auto switching test.
+     */
+    class TestManualAutoSwitch implements TestRoutine
+    {
+        @Override
+        public void execute(CaptureRequest.Builder rawBurstBuilder,
+                SimpleCaptureCallback rawCaptureCallback,
+                SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception
+        {
+            // create a capture request builder to preserve all the original values
+            CaptureRequest.Builder originBuilder = mCamera.createCaptureRequest(
+                    CameraDevice.TEMPLATE_STILL_CAPTURE);
+            copyBurstRequetBuilder(originBuilder, rawBurstBuilder);
+
+            // build burst capture
+            ArrayList<CaptureRequest> rawRequestList = createBurstRequest(rawBurstBuilder);
+
+            // submit captrue but ignore
+            mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler);
+
+            // drain the capture result
+            drainQueues(rawReaderListener, rawCaptureCallback);
+
+            // reset and build capture with 3A
+            copyBurstRequetBuilder(rawBurstBuilder, originBuilder);
+            rawRequestList = createBurstRequestWith3A(rawBurstBuilder);
+
+            // submit captrue but ignore
+            mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler);
+
+            // drain the capture result
+            drainQueues(rawReaderListener, rawCaptureCallback);
+
+            // reset and rebuild manual raw burst capture
+            copyBurstRequetBuilder(rawBurstBuilder, originBuilder);
+            rawRequestList = createBurstRequest(rawBurstBuilder);
+
+            // submit capture
+            Log.i(TAG, "Submitting Burst Request.");
+            mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler);
+
+            // verify metadata
+            for (int i = 0; i < MAX_FRAMES_BURST; i++) {
+                CaptureResult result = rawCaptureCallback.getCaptureResult(
+                        CAPTURE_IMAGE_TIMEOUT_MS);
+
+                long resultExposure = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
+                int resultSensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY);
+                int resultEdgeMode = result.get(CaptureResult.EDGE_MODE);
+                int resultNoiseReductionMode = result.get(
+                        CaptureResult.NOISE_REDUCTION_MODE);
+                long desiredExposure = rawRequestList.get(i).get(
+                        CaptureRequest.SENSOR_EXPOSURE_TIME);
+                int desiredSensitivity = rawRequestList.get(i).get(
+                        CaptureRequest.SENSOR_SENSITIVITY);
+
+                Log.i(TAG, String.format(
+                        "Received capture result, exposure = %d, sensitivity = %d. "
+                                + "Requested exposure = %d, sensitivity = %d.",
+                        resultExposure,
+                        resultSensitivity, desiredExposure, desiredSensitivity));
+
+                mCollector.expectTrue(String.format("Edge mode is not turned off."),
+                        resultEdgeMode == CaptureRequest.EDGE_MODE_OFF);
+
+                mCollector.expectTrue(String.format("Noise reduction is not turned off."),
+                        resultNoiseReductionMode
+                        == CaptureRequest.NOISE_REDUCTION_MODE_OFF);
+
+                mCollector.expectTrue(
+                        String.format("Exposure value is greater than requested: "
+                                + "requested = %d, result = %d.",
+                                desiredExposure, resultExposure),
+                                resultExposure <= desiredExposure);
+
+                mCollector.expectTrue(
+                        String.format("Sensitivity value is greater than requested: "
+                                + "requested = %d, result = %d.",
+                                desiredSensitivity, resultSensitivity),
+                                resultSensitivity <= desiredSensitivity);
+            }
+
+        }
+    }
+
+    /**
+     * Implementation of timestamp test
+     */
+    class TestTimestamp implements TestRoutine
+    {
+        private final double THRESHOLD = 5000000.0; // 5ms
+        private final long EXPOSURE_MULTIPLIERS_PRIVATE[] = {
+                1, 1, 1 };
+        private final int SENSITIVITY_MLTIPLIERS_PRIVATE[] = {
+                1, 1, 1 };
+        private final int MAX_FRAMES_BURST_PRIVATE =
+                EXPOSURE_MULTIPLIERS_PRIVATE.length * SENSITIVITY_MLTIPLIERS_PRIVATE.length;
+
+        @Override
+        public void execute(Builder rawBurstBuilder, SimpleCaptureCallback rawCaptureCallback,
+                SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception {
+            // prepare some local variables
+            ArrayList<Long> sensorTime = new ArrayList<Long>(MAX_FRAMES_BURST_PRIVATE);
+
+            // build burst capture
+            ArrayList<CaptureRequest> rawRequestList = createBurstRequest(rawBurstBuilder,
+                    EXPOSURE_MULTIPLIERS_PRIVATE, SENSITIVITY_MLTIPLIERS_PRIVATE);
+
+            // submit capture while recording timestamp
+            Log.i(TAG, "Submitting Burst Request.");
+            mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler);
+
+            // receive frames while recording timestamp
+            for (int i = 0; i < MAX_FRAMES_BURST_PRIVATE; i++) {
+                CaptureResult result = rawCaptureCallback.getCaptureResult(
+                        CAPTURE_IMAGE_TIMEOUT_MS);
+                long resultExposure = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
+                int resultSensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY);
+                long resultTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
+                Log.i(TAG, String.format(
+                        "Received capture result, exposure = %d, sensitivity = %d, timestamp = %d",
+                        resultExposure, resultSensitivity, resultTimestamp));
+
+                sensorTime.add(resultTimestamp);
+            }
+
+            // compare sensor time and compute the difference
+            ArrayList<Long> deltaList = new ArrayList<Long>();
+            for (int i = 1; i < MAX_FRAMES_BURST_PRIVATE; i++)
+            {
+                deltaList.add(sensorTime.get(i) - sensorTime.get(i - 1));
+            }
+
+            // compute the average and standard deviation of the differences
+            double average = 0.0;
+            for (int i = 0; i < deltaList.size(); i++)
+            {
+                average += deltaList.get(i);
+            }
+            average /= deltaList.size();
+
+            double stddev = 0.0;
+            for (int i = 0; i < deltaList.size(); i++)
+            {
+                double diff = deltaList.get(i) - average;
+                stddev += diff * diff;
+            }
+            stddev = Math.sqrt(stddev / deltaList.size());
+
+            Log.i(TAG, String.format("average = %.2f, stddev = %.2f", average, stddev));
+
+            StringBuilder sensorTimestampMessage = new StringBuilder();
+            for (int i = 0; i < sensorTime.size(); i++)
+            {
+                sensorTimestampMessage.append("frame [");
+                sensorTimestampMessage.append(i);
+                sensorTimestampMessage.append("] SENSOR_TIMESTAMP = ");
+                sensorTimestampMessage.append(sensorTime.get(i));
+                sensorTimestampMessage.append("\n");
+            }
+
+            mCollector.expectLessOrEqual(
+                    "The standard deviation of frame interval is larger then threshold: " +
+                    String.format("stddev = %.2f, threshold = %.2f.\n", stddev, THRESHOLD) +
+                    sensorTimestampMessage.toString(),
+                    THRESHOLD, stddev);
+        }
+    }
+
+    /**
+     * Check sensor capability prior to the test.
+     *
+     * @return true if the it is has the capability to execute the test.
+     */
+    private boolean checkCapability(ArrayList<Integer> supportedRawList) {
+        // make sure the sensor has manual support
+        if (!mStaticInfo.isCapabilitySupported(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
+            Log.w(TAG, "Full hardware level is not supported");
+            return false;
+        }
+
+        // get the list of supported RAW format
+        StreamConfigurationMap config = mStaticInfo.getValueFromKeyNonNull(
+                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+        // check for the RAW support
+        supportedRawList.clear();
+        for (int rawFormat : RAW_FORMATS) {
+            if (!config.isOutputSupportedFor(rawFormat)) {
+                continue;
+            }
+            supportedRawList.add(rawFormat);
+        }
+
+        if (supportedRawList.size() == 0)
+        {
+            Log.w(TAG, "RAW output is not supported!");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Return the sensor format to human readable string.
+     *
+     * @param format Sensor image format.
+     * @return Human readable string.
+     */
+    private String imageFormatToString(int format) {
+        switch (format) {
+            case ImageFormat.RAW10:
+                return "RAW10";
+            case ImageFormat.RAW_SENSOR:
+                return "RAW_SENSOR";
+        }
+
+        return "Unknown";
+    }
+
+    /**
+     * Setting up various classes prior to the request, e.g.: capture size, builder, callback and
+     * listener
+     *
+     * @return initialized variables that can be directly fed into prepareCaptureAndStartPreview().
+     */
+    private CaptureSetup initCaptureSetupForPreviewAndRaw() throws Exception
+    {
+        // capture size
+        Size previewSize = mOrderedPreviewSizes.get(0);
+        Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
+        Size rawSize = new Size(activeArray.width(), activeArray.height());
+
+        // builder
+        CaptureRequest.Builder previewCaptureBuilder = mCamera.createCaptureRequest(
+                CameraDevice.TEMPLATE_PREVIEW);
+        CaptureRequest.Builder rawCaptureBuilder = mCamera.createCaptureRequest(
+                CameraDevice.TEMPLATE_STILL_CAPTURE);
+
+        // callback
+        SimpleCaptureCallback previewCaptureCallback = new SimpleCaptureCallback();
+        SimpleCaptureCallback rawCaptureCallback = new SimpleCaptureCallback();
+        SimpleImageReaderListener rawReaderListener = new SimpleImageReaderListener();
+
+        CaptureSetup setup = new CaptureSetup(previewSize, rawSize, previewCaptureBuilder,
+                rawCaptureBuilder, previewCaptureCallback, rawCaptureCallback, rawReaderListener);
+
+        return setup;
+    }
+
+    /**
+     * Construct an array of burst request with manual exposure and sensitivity.
+     * <p>
+     * For each capture request, 3A and post processing (noise reduction, sharpening, etc) will be
+     * turned off. Then exposure and sensitivity value will be configured, which are determined by
+     * EXPOSURE_MULIPLIERS and SENSITIVITY_MULTIPLIERS.
+     * </p>
+     *
+     * @param rawBurstBuilder The builder needs to have targets setup.
+     * @return An array list capture request for burst.
+     */
+    private ArrayList<CaptureRequest> createBurstRequest(CaptureRequest.Builder rawBurstBuilder)
+    {
+        return createBurstRequest(rawBurstBuilder, EXPOSURE_MULTIPLIERS, SENSITIVITY_MLTIPLIERS);
+    }
+
+    private ArrayList<CaptureRequest> createBurstRequest(CaptureRequest.Builder rawBurstBuilder,
+            long[] exposureMultipliers, int[] sensitivityMultipliers) {
+        // set manual mode
+        rawBurstBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
+        rawBurstBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF);
+        rawBurstBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE,
+                CaptureRequest.NOISE_REDUCTION_MODE_OFF);
+        rawBurstBuilder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_OFF);
+        // exposure has higher priority over frame duration; therefore the frame readout time:
+        // exposure time + overhead
+        rawBurstBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, 0L);
+
+        // get the exposure and sensitivity range
+        Range<Long> exposureRangeNs = new Range<Long>(mStaticInfo.getExposureMinimumOrDefault(),
+                mStaticInfo.getExposureMaximumOrDefault());
+
+        Range<Integer> isoRange = new Range<Integer>(mStaticInfo.getSensitivityMinimumOrDefault(),
+                mStaticInfo.getSensitivityMaximumOrDefault());
+
+        Log.i(TAG, String.format("Exposure time - max: %d, min: %d.", exposureRangeNs.getUpper(),
+                exposureRangeNs.getLower()));
+        Log.i(TAG, String.format("Sensitivity - max: %d, min: %d.", isoRange.getUpper(),
+                isoRange.getLower()));
+
+        // building burst request
+        int maxFramesBurst = exposureMultipliers.length * sensitivityMultipliers.length;
+        Log.i(TAG, String.format("Setting up burst = %d frames.", maxFramesBurst));
+        ArrayList<CaptureRequest> rawRequestList = new ArrayList<CaptureRequest>(maxFramesBurst);
+
+        for (int i = 0; i < exposureMultipliers.length; i++) {
+            for (int j = 0; j < sensitivityMultipliers.length; j++) {
+                long desiredExposure = Math.min(
+                        exposureRangeNs.getLower() * exposureMultipliers[i],
+                        exposureRangeNs.getUpper());
+
+                int desiredSensitivity =
+                        Math.min(isoRange.getLower() * sensitivityMultipliers[j],
+                                isoRange.getUpper());
+
+                rawBurstBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, desiredExposure);
+                rawBurstBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, desiredSensitivity);
+
+                rawRequestList.add(rawBurstBuilder.build());
+            }
+        }
+        return rawRequestList;
+    }
+
+    /**
+     * Construct an array of burst request with 3A
+     * <p>
+     * For each capture request, 3A and post processing (noise reduction, sharpening, etc) will be
+     * turned on.
+     * </p>
+     *
+     * @param rawBurstBuilder The builder needs to have targets setup.
+     * @return An array list capture request for burst.
+     */
+    private ArrayList<CaptureRequest> createBurstRequestWith3A(
+            CaptureRequest.Builder rawBurstBuilder)
+    {
+        // set 3A mode to simulate regular still capture
+        rawBurstBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
+        rawBurstBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
+        rawBurstBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE,
+                CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
+        rawBurstBuilder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_HIGH_QUALITY);
+
+        // building burst request
+        Log.i(TAG, String.format("Setting up burst = %d frames.", MAX_FRAMES_BURST));
+        ArrayList<CaptureRequest> rawRequestList = new ArrayList<CaptureRequest>(MAX_FRAMES_BURST);
+
+        for (int i = 0; i < MAX_FRAMES_BURST; i++) {
+            rawRequestList.add(rawBurstBuilder.build());
+        }
+
+        return rawRequestList;
+    }
+
+    /**
+     * An utility method to copy capture request builders. This is used for recovery purpose to
+     * reverse the changes we made to the builder.
+     *
+     * @param dst the builder to write into.
+     * @param src the builder that needs to be copied.
+     */
+    private void copyBurstRequetBuilder(CaptureRequest.Builder dst, CaptureRequest.Builder src)
+    {
+        dst.set(CaptureRequest.CONTROL_AE_MODE, src.get(CaptureRequest.CONTROL_AE_MODE));
+        dst.set(CaptureRequest.CONTROL_AWB_MODE, src.get(CaptureRequest.CONTROL_AWB_MODE));
+        dst.set(CaptureRequest.NOISE_REDUCTION_MODE, src.get(CaptureRequest.NOISE_REDUCTION_MODE));
+        dst.set(CaptureRequest.EDGE_MODE, src.get(CaptureRequest.EDGE_MODE));
+        dst.set(CaptureRequest.SENSOR_FRAME_DURATION,
+                src.get(CaptureRequest.SENSOR_FRAME_DURATION));
+        dst.set(CaptureRequest.SENSOR_EXPOSURE_TIME, src.get(CaptureRequest.SENSOR_EXPOSURE_TIME));
+        dst.set(CaptureRequest.SENSOR_SENSITIVITY, src.get(CaptureRequest.SENSOR_SENSITIVITY));
+    }
+
+    /**
+     * Draining the image reader and capture callback queue
+     *
+     * @param readerListener Image reader listener needs to be drained.
+     * @param captureCallback Capture callback needs to be drained.
+     * @throws Exception Exception from the queue.
+     */
+    private void drainQueues(SimpleImageReaderListener readerListener,
+            SimpleCaptureCallback captureCallback) throws Exception
+    {
+        for (int i = 0; i < MAX_FRAMES_BURST; i++) {
+            Image image = readerListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+            image.close();
+
+            CaptureResult result = captureCallback.getCaptureResult(
+                    CAPTURE_IMAGE_TIMEOUT_MS);
+            long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
+            Log.d(TAG, String.format("timestamp = %d", timestamp));
+        }
+    }
+
+    /**
+     * Stop preview and remove the target surfaces inside the CaptureRequest.Builder.
+     *
+     * @param previewBuilder Configured builder for preview.
+     * @param rawBurstBuilder Configured builder for RAW.
+     * @throws Exception Exceptions from stopPreview.
+     */
+    private void stopPreviewAndClearSurface(CaptureRequest.Builder previewBuilder,
+            CaptureRequest.Builder rawBurstBuilder) throws Exception
+    {
+        previewBuilder.removeTarget(mPreviewSurface);
+        rawBurstBuilder.removeTarget(mPreviewSurface);
+        rawBurstBuilder.removeTarget(mReaderSurface);
+
+        stopPreview();
+    }
+
+    private void performTestRoutine(TestRoutine routine) throws Exception
+    {
+        for (String id : mCameraIds) {
+            try {
+                openDevice(id);
+
+                ArrayList<Integer> supportedRawList = new ArrayList<Integer>(RAW_FORMATS.length);
+                if (!checkCapability(supportedRawList)) {
+                    Log.i(TAG, "Capability is not supported on camera " + id
+                            + ". Skip the test.");
+                    continue;
+                }
+
+                // test each supported RAW format
+                for (int rawFormat : supportedRawList) {
+                    Log.i(TAG, "Testing format " + imageFormatToString(rawFormat) + ".");
+
+                    // prepare preview and still RAW capture
+                    CaptureSetup captureSetup = initCaptureSetupForPreviewAndRaw();
+
+                    Size previewCaptureSize = captureSetup.getPreviewCaptureSize();
+                    Size rawCaptureSize = captureSetup.getRawCaptureSize();
+
+                    CaptureRequest.Builder previewBuilder = captureSetup.getPreviewRequestBuilder();
+                    CaptureRequest.Builder rawBurstBuilder = captureSetup.getRawRequestBuilder();
+
+                    SimpleCaptureCallback previewCaptureCallback =
+                            captureSetup.getPreviewCaptureCallback();
+                    SimpleCaptureCallback rawCaptureCallback = captureSetup.getRawCaptureCallback();
+                    SimpleImageReaderListener rawReaderListener = captureSetup
+                            .getRawReaderListener();
+
+                    // start preview and prepare RAW capture
+                    prepareCaptureAndStartPreview(previewBuilder, rawBurstBuilder,
+                            previewCaptureSize, rawCaptureSize, rawFormat, previewCaptureCallback,
+                            MAX_FRAMES_BURST, rawReaderListener);
+
+                    // execute test routine
+                    routine.execute(rawBurstBuilder, rawCaptureCallback, rawReaderListener,
+                            rawFormat);
+
+                    // clear out the surface and camera session
+                    stopPreviewAndClearSurface(previewBuilder, rawBurstBuilder);
+                    closeImageReader();
+                }
+            } finally {
+                closeDevice();
+            }
+        }
+    }
+}
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 29c7362..b3bfd64 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -1089,16 +1089,22 @@
             mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
                     CaptureRequest.CONTROL_AE_MODE_ON);
             mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0);
-            mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
             mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER,
                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
+            // if AE lock is not supported, expect the control key to be non-exist or false
+            if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) {
+                mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
+            }
 
             mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER,
                     CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
 
             mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
                     CaptureRequest.CONTROL_AWB_MODE_AUTO);
-            mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
+            // if AWB lock is not supported, expect the control key to be non-exist or false
+            if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) {
+                mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
+            }
 
             // Check 3A regions.
             if (VERBOSE) {
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 872f951..e4a683d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -16,8 +16,6 @@
 
 package android.hardware.camera2.cts;
 
-import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
-
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.ImageFormat;
@@ -546,7 +544,8 @@
         StreamConfigurationMap configMap =
                 properties.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
         Size[] availableSizes = configMap.getOutputSizes(format);
-        assertArrayNotEmpty(availableSizes, "availableSizes should not be empty");
+        assertArrayNotEmpty(availableSizes, "availableSizes should not be empty for format: "
+                + format);
         if (VERBOSE) Log.v(TAG, "Supported sizes are: " + Arrays.deepToString(availableSizes));
         return availableSizes;
     }
@@ -605,7 +604,7 @@
      * Get sorted (descending order) size list for given format. Remove the sizes larger than
      * the bound. If the bound is null, don't do the size bound filtering.
      */
-    static private List<Size> getSortedSizesForFormat(String cameraId,
+    static public List<Size> getSortedSizesForFormat(String cameraId,
             CameraManager cameraManager, int format, Size bound) throws CameraAccessException {
         Comparator<Size> comparator = new SizeComparator();
         Size[] sizes = getSupportedSizeForFormat(format, cameraId, cameraManager);
@@ -1018,4 +1017,114 @@
         }
         return resultRegions;
     }
+
+    /**
+     * Copy source image data to destination image.
+     *
+     * @param src The source image to be copied from.
+     * @param dst The destination image to be copied to.
+     * @throws IllegalArgumentException If the source and destination images have
+     *             different format, or one of the images is not copyable.
+     */
+    public static void imageCopy(Image src, Image dst) {
+        if (src == null || dst == null) {
+            throw new IllegalArgumentException("Images should be non-null");
+        }
+        if (src.getFormat() != dst.getFormat()) {
+            throw new IllegalArgumentException("Src and dst images should have the same format");
+        }
+        if (src.isOpaque() || dst.isOpaque()) {
+            throw new IllegalArgumentException("Opaque image is not copyable");
+        }
+
+        // TODO: check the owner of the dst image, it must be from ImageWriter, other source may
+        // not be writable. Maybe we should add an isWritable() method in image class.
+
+        Plane[] srcPlanes = src.getPlanes();
+        Plane[] dstPlanes = dst.getPlanes();
+        ByteBuffer srcBuffer = null;
+        ByteBuffer dstBuffer = null;
+        for (int i = 0; i < srcPlanes.length; i++) {
+            srcBuffer = srcPlanes[i].getBuffer();
+            int srcPos = srcBuffer.position();
+            srcBuffer.rewind();
+            dstBuffer = dstPlanes[i].getBuffer();
+            dstBuffer.rewind();
+            dstBuffer.put(srcBuffer);
+            srcBuffer.position(srcPos);
+            dstBuffer.rewind();
+        }
+    }
+
+    /**
+     * <p>
+     * Checks whether the two images are strongly equal.
+     * </p>
+     * <p>
+     * Two images are strongly equal if and only if the data, formats, sizes, and
+     * timestamps are same. For opaque images ({@link Image#isOpaque()} returns
+     * true), the image data is not not accessible thus the data comparison is
+     * effectively skipped as the number of planes is zero.
+     * </p>
+     * <p>
+     * Note that this method compares the pixel data even outside of the crop
+     * region, which may not be necessary for general use case.
+     * </p>
+     *
+     * @param lhsImg First image to be compared with.
+     * @param rhsImg Second image to be compared with.
+     * @return true if the two images are equal, false otherwise.
+     * @throws IllegalArgumentException If either of image is null.
+     */
+    public static boolean isImageStronglyEqual(Image lhsImg, Image rhsImg) {
+        if (lhsImg == null || rhsImg == null) {
+            throw new IllegalArgumentException("Images should be non-null");
+        }
+
+        if (lhsImg.getFormat() != rhsImg.getFormat()) {
+            Log.i(TAG, "lhsImg format " + lhsImg.getFormat() + " is different with rhsImg format "
+                    + rhsImg.getFormat());
+            return false;
+        }
+
+        if (lhsImg.getWidth() != rhsImg.getWidth()) {
+            Log.i(TAG, "lhsImg width " + lhsImg.getWidth() + " is different with rhsImg width "
+                    + rhsImg.getWidth());
+            return false;
+        }
+
+        if (lhsImg.getHeight() != rhsImg.getHeight()) {
+            Log.i(TAG, "lhsImg height " + lhsImg.getHeight() + " is different with rhsImg height "
+                    + rhsImg.getHeight());
+            return false;
+        }
+
+        if (lhsImg.getTimestamp() != rhsImg.getTimestamp()) {
+            Log.i(TAG, "lhsImg timestamp " + lhsImg.getTimestamp()
+                    + " is different with rhsImg timestamp " + rhsImg.getTimestamp());
+            return false;
+        }
+
+        if (!lhsImg.getCropRect().equals(rhsImg.getCropRect())) {
+            Log.i(TAG, "lhsImg crop rect " + lhsImg.getCropRect()
+                    + " is different with rhsImg crop rect " + rhsImg.getCropRect());
+            return false;
+        }
+
+        // Compare data inside of the image.
+        Plane[] lhsPlanes = lhsImg.getPlanes();
+        Plane[] rhsPlanes = rhsImg.getPlanes();
+        ByteBuffer lhsBuffer = null;
+        ByteBuffer rhsBuffer = null;
+        for (int i = 0; i < lhsPlanes.length; i++) {
+            lhsBuffer = lhsPlanes[i].getBuffer();
+            rhsBuffer = rhsPlanes[i].getBuffer();
+            if (!lhsBuffer.equals(rhsBuffer)) {
+                Log.i(TAG, "byte buffers for plane " +  i + " don't matach.");
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
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 1f2792c..f3a0cc0 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -1046,7 +1046,9 @@
     private void aeAutoModeTestLock(int mode) throws Exception {
         CaptureRequest.Builder requestBuilder =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
-        requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+        if (mStaticInfo.isAeLockSupported()) {
+            requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+        }
         requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mode);
         configurePreviewOutput(requestBuilder);
 
@@ -1077,9 +1079,12 @@
         SimpleCaptureCallback listener =  new SimpleCaptureCallback();
 
         CaptureResult[] resultsDuringLock = new CaptureResult[numCapturesDuringLock];
+        boolean canSetAeLock = mStaticInfo.isAeLockSupported();
 
         // Reset the AE lock to OFF, since we are reusing this builder many times
-        requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+        if (canSetAeLock) {
+            requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+        }
 
         // Just send several captures with auto AE, lock off.
         CaptureRequest request = requestBuilder.build();
@@ -1088,6 +1093,11 @@
         }
         waitForNumResults(listener, NUM_CAPTURES_BEFORE_LOCK);
 
+        if (!canSetAeLock) {
+            // Without AE lock, the remaining tests items won't work
+            return;
+        }
+
         // Then fire several capture to lock the AE.
         requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
 
@@ -1112,7 +1122,7 @@
 
         // Can't read manual sensor/exposure settings without manual sensor
         if (mStaticInfo.isCapabilitySupported(
-                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
             int sensitivityLocked =
                     getValueNotNull(resultsDuringLock[0], CaptureResult.SENSOR_SENSITIVITY);
             long expTimeLocked =
@@ -1475,6 +1485,7 @@
     private void awbModeAndLockTestByCamera() throws Exception {
         int[] awbModes = mStaticInfo.getAwbAvailableModesChecked();
         Size maxPreviewSize = mOrderedPreviewSizes.get(0);
+        boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
         CaptureRequest.Builder requestBuilder =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
         startPreview(requestBuilder, maxPreviewSize, /*listener*/null);
@@ -1490,7 +1501,7 @@
             verifyCaptureResultForKey(CaptureResult.CONTROL_AWB_MODE, mode, listener,
                     NUM_FRAMES_VERIFIED);
 
-            if (mode == CameraMetadata.CONTROL_AWB_MODE_AUTO) {
+            if (mode == CameraMetadata.CONTROL_AWB_MODE_AUTO && canSetAwbLock) {
                 // Verify color correction transform and gains stay unchanged after a lock.
                 requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
                 listener = new SimpleCaptureCallback();
@@ -1503,7 +1514,10 @@
                 }
 
             }
-            verifyAwbCaptureResultUnchanged(listener, NUM_FRAMES_VERIFIED);
+            // Don't verify auto mode result if AWB lock is not supported
+            if (mode != CameraMetadata.CONTROL_AWB_MODE_AUTO || canSetAwbLock) {
+                verifyAwbCaptureResultUnchanged(listener, NUM_FRAMES_VERIFIED);
+            }
         }
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
index d5972e2..807aa29 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
@@ -548,7 +548,8 @@
             outputSurfaces.add(captureSurface);
         }
 
-        CaptureRequest.Builder request = prepareCaptureRequestForSurfaces(outputSurfaces);
+        CaptureRequest.Builder request = prepareCaptureRequestForSurfaces(outputSurfaces,
+                CameraDevice.TEMPLATE_STILL_CAPTURE);
         request.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
                 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON);
         CameraTestUtils.SimpleCaptureCallback resultListener =
@@ -578,18 +579,4 @@
 
         return ret;
     }
-
-    private CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces)
-            throws Exception {
-        createSession(surfaces);
-
-        CaptureRequest.Builder captureBuilder =
-                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
-        assertNotNull("Fail to get captureRequest", captureBuilder);
-        for (Surface surface : surfaces) {
-            captureBuilder.addTarget(surface);
-        }
-
-        return captureBuilder;
-    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 8619f73..06561d4 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -84,6 +84,10 @@
             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING;
     private static final int RAW =
             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW;
+    private static final int YUV_REPROCESS =
+            CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING;
+    private static final int OPAQUE_REPROCESS =
+            CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING;
 
     @Override
     public void setContext(Context context) {
@@ -222,6 +226,7 @@
                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE                , LIMITED  ,   NONE                 );
                 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , LEGACY   ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES                  , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS                   , OPT      ,   YUV_REPROCESS, OPAQUE_REPROCESS);
                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC                     , LEGACY   ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING            , LEGACY   ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW                      , LEGACY   ,   BC                   );
@@ -383,6 +388,10 @@
                      maxYuvSize.getHeight() <= sensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) &&
                      maxYuvSize.getHeight() >= sensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN));
 
+            // No need to do null check since framework will generate the key if HAL don't supply
+            boolean haveAeLock = c.get(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
+            boolean haveAwbLock = c.get(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
+
             // Ensure that YUV output is fast enough - needs to be at least 20 fps
 
             long maxYuvRate =
@@ -438,14 +447,25 @@
                                 mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND),
                         haveFastSyncLatency);
                 assertTrue(
-                        "Active array size and max YUV size should be similar",
+                        String.format("BURST-capable camera device %s max YUV size %s should be" +
+                                "close to active array size %s",
+                                mIds[counter], maxYuvSize.toString(), sensorSize.toString()),
                         maxYuvMatchSensor);
+                assertTrue(
+                        String.format("BURST-capable camera device %s does not support AE lock",
+                                mIds[counter]),
+                        haveAeLock);
+                assertTrue(
+                        String.format("BURST-capable camera device %s does not support AWB lock",
+                                mIds[counter]),
+                        haveAwbLock);
             } else {
                 assertTrue(
                         String.format("Camera device %s has all the requirements for BURST" +
                                 " capability but does not report it!", mIds[counter]),
                         !(haveMaxYuv && haveMaxYuvRate && haveFastAeTargetFps &&
-                                haveFastSyncLatency && maxYuvMatchSensor));
+                                haveFastSyncLatency && maxYuvMatchSensor &&
+                                haveAeLock && haveAwbLock));
             }
 
             counter++;
@@ -453,6 +473,72 @@
     }
 
     /**
+     * Check reprocessing capabilities.
+     */
+    public void testReprocessingCharacteristics() {
+        int counter = 0;
+
+        for (CameraCharacteristics c : mCharacteristics) {
+            Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mIds[counter]);
+
+            int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+            assertNotNull("android.request.availableCapabilities must never be null",
+                    capabilities);
+            boolean supportYUV = arrayContains(capabilities,
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
+            boolean supportOpaque = arrayContains(capabilities,
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING);
+            StreamConfigurationMap configs =
+                    c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+            Integer maxNumInputStreams =
+                    c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS);
+
+            int[] inputFormats = configs.getInputFormats();
+
+            assertFalse("Doesn't support reprocessing but report input format: " +
+                    Arrays.toString(inputFormats), !supportYUV && !supportOpaque &&
+                    inputFormats.length > 0);
+
+            assertFalse("Doesn't support reprocessing but max number of input stream is " +
+                    maxNumInputStreams, !supportYUV && !supportOpaque &&
+                    maxNumInputStreams != null && maxNumInputStreams != 0);
+
+            if (supportYUV || supportOpaque) {
+                assertTrue("Support reprocessing but max number of input stream is " +
+                        maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0);
+
+                // Verify mandatory input formats are supported
+                assertTrue("YUV_420_888 input must be supported for YUV reprocessing",
+                        !supportYUV || arrayContains(inputFormats, ImageFormat.YUV_420_888));
+                assertTrue("PRIVATE input must be supported for OPAQUE reprocessing",
+                        !supportOpaque || arrayContains(inputFormats, ImageFormat.PRIVATE));
+
+                for (int input : inputFormats) {
+                    // Verify mandatory output formats are supported
+                    int[] outputFormats = configs.getValidOutputFormatsForInput(input);
+                    assertTrue("YUV_420_888 output must be supported for reprocessing",
+                            arrayContains(outputFormats, ImageFormat.YUV_420_888));
+                    assertTrue("JPEG output must be supported for reprocessing",
+                            arrayContains(outputFormats, ImageFormat.JPEG));
+
+                    // Verify camera can output the reprocess input formats and sizes.
+                    Size[] inputSizes = configs.getInputSizes(input);
+                    Size[] outputSizes = configs.getOutputSizes(input);
+                    assertTrue("no input size supported for format " + input,
+                            inputSizes.length > 0);
+                    assertTrue("no output size supported for format " + input,
+                            outputSizes.length > 0);
+
+                    for (Size inputSize : inputSizes) {
+                        assertTrue("Camera must be able to output the supported reprocessing " +
+                            "input size", arrayContains(outputSizes, inputSize));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Cross-check StreamConfigurationMap output
      */
     public void testStreamConfigurationMap() {
@@ -534,29 +620,30 @@
                                 minDuration >= 0);
                     }
 
-                    ImageReader testReader = ImageReader.newInstance(
-                        size.getWidth(),
-                        size.getHeight(),
-                        format,
-                        1);
-                    Surface testSurface = testReader.getSurface();
+                    // todo: test opaque image reader when it's supported.
+                    if (format != ImageFormat.PRIVATE) {
+                        ImageReader testReader = ImageReader.newInstance(
+                            size.getWidth(),
+                            size.getHeight(),
+                            format,
+                            1);
+                        Surface testSurface = testReader.getSurface();
 
-                    assertTrue(
-                        String.format("isOutputSupportedFor fails for config %s, format %d",
-                                size.toString(), format),
-                        config.isOutputSupportedFor(testSurface));
+                        assertTrue(
+                            String.format("isOutputSupportedFor fails for config %s, format %d",
+                                    size.toString(), format),
+                            config.isOutputSupportedFor(testSurface));
 
-                    testReader.close();
-
+                        testReader.close();
+                    }
                 } // sizes
 
                 // Try an invalid size in this format, should round
                 Size invalidSize = findInvalidSize(supportedSizes);
-                // WAR: the intended threshold is 1920, but to counter the bug
-                // in Lollipop framework, we need to set it to 1080 here.
-                // The threshold will be changed back to 1920 in next Android release.
-                int MAX_ROUNDING_WIDTH = 1080;
-                if (invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) {
+                int MAX_ROUNDING_WIDTH = 1920;
+                // todo: test opaque image reader when it's supported.
+                if (format != ImageFormat.PRIVATE &&
+                        invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) {
                     ImageReader testReader = ImageReader.newInstance(
                                                                      invalidSize.getWidth(),
                                                                      invalidSize.getHeight(),
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/FlashlightTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/FlashlightTest.java
new file mode 100644
index 0000000..44b13c3
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/FlashlightTest.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.cts;
+
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
+import android.hardware.camera2.cts.helpers.StaticMetadata;
+import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
+import android.util.Log;
+import android.os.SystemClock;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * <p>Tests for flashlight API.</p>
+ */
+public class FlashlightTest extends Camera2AndroidTestCase {
+    private static final String TAG = "FlashlightTest";
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+    private static final int TORCH_DURATION_MS = 1000;
+    private static final int TORCH_TIMEOUT_MS = 3000;
+    private static final int NUM_REGISTERS = 10;
+
+    private ArrayList<String> mFlashCameraIdList;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // initialize the list of cameras that have a flash unit so it won't interfere with
+        // flash tests.
+        mFlashCameraIdList = new ArrayList<String>();
+        for (String id : mCameraIds) {
+            StaticMetadata info =
+                    new StaticMetadata(mCameraManager.getCameraCharacteristics(id),
+                                       CheckLevel.ASSERT, /*collector*/ null);
+            if (info.hasFlash()) {
+                mFlashCameraIdList.add(id);
+            }
+        }
+    }
+
+    public void testSetTorchModeOnOff() throws Exception {
+        if (mFlashCameraIdList.size() == 0)
+            return;
+
+        // reset flash status for all devices with a flash unit
+        for (String id : mFlashCameraIdList) {
+            resetTorchModeStatus(id);
+        }
+
+        // turn on and off torch mode one by one
+        for (String id : mFlashCameraIdList) {
+            CameraManager.TorchCallback torchListener = mock(CameraManager.TorchCallback.class);
+            mCameraManager.registerTorchCallback(torchListener, mHandler); // should get OFF
+
+            mCameraManager.setTorchMode(id, true); // should get ON
+            SystemClock.sleep(TORCH_DURATION_MS);
+            mCameraManager.setTorchMode(id, false); // should get OFF
+
+            // verify corrected numbers of callbacks
+            verify(torchListener, timeout(TORCH_TIMEOUT_MS).
+                    times(2)).onTorchModeChanged(id, false);
+            verify(torchListener, timeout(TORCH_TIMEOUT_MS).
+                    times(mFlashCameraIdList.size() + 1)).
+                    onTorchModeChanged(anyString(), eq(false));
+            verify(torchListener, timeout(TORCH_TIMEOUT_MS).
+                    times(1)).onTorchModeChanged(id, true);
+            verify(torchListener, timeout(TORCH_TIMEOUT_MS).
+                    times(1)).onTorchModeChanged(anyString(), eq(true));
+            verify(torchListener, timeout(TORCH_TIMEOUT_MS).never()).
+                    onTorchModeUnavailable(anyString());
+
+            mCameraManager.unregisterTorchCallback(torchListener);
+        }
+
+        // turn on all torch modes at once
+        if (mFlashCameraIdList.size() >= 2) {
+            CameraManager.TorchCallback torchListener = mock(CameraManager.TorchCallback.class);
+            mCameraManager.registerTorchCallback(torchListener, mHandler); // should get OFF.
+
+            for (String id : mFlashCameraIdList) {
+                // should get ON for this ID.
+                // may get OFF for previously-on IDs.
+                mCameraManager.setTorchMode(id, true);
+            }
+
+            SystemClock.sleep(TORCH_DURATION_MS);
+
+            for (String id : mFlashCameraIdList) {
+                // should get OFF if not turned off previously.
+                mCameraManager.setTorchMode(id, false);
+            }
+
+            verify(torchListener, timeout(TORCH_TIMEOUT_MS).times(mFlashCameraIdList.size())).
+                    onTorchModeChanged(anyString(), eq(true));
+            // one more off for each id due to callback registeration.
+            verify(torchListener, timeout(TORCH_TIMEOUT_MS).
+                    times(mFlashCameraIdList.size() * 2)).
+                    onTorchModeChanged(anyString(), eq(false));
+
+            mCameraManager.unregisterTorchCallback(torchListener);
+        }
+    }
+
+    public void testTorchCallback() throws Exception {
+        if (mFlashCameraIdList.size() == 0)
+            return;
+
+        // reset torch mode status
+        for (String id : mFlashCameraIdList) {
+            resetTorchModeStatus(id);
+        }
+
+        CameraManager.TorchCallback torchListener = mock(CameraManager.TorchCallback.class);
+
+        for (int i = 0; i < NUM_REGISTERS; i++) {
+            // should get OFF for all cameras with a flash unit.
+            mCameraManager.registerTorchCallback(torchListener, mHandler);
+            mCameraManager.unregisterTorchCallback(torchListener);
+        }
+
+        verify(torchListener, timeout(TORCH_TIMEOUT_MS).
+                times(NUM_REGISTERS * mFlashCameraIdList.size())).
+                onTorchModeChanged(anyString(), eq(false));
+        verify(torchListener, timeout(TORCH_TIMEOUT_MS).never()).
+                onTorchModeChanged(anyString(), eq(true));
+        verify(torchListener, timeout(TORCH_TIMEOUT_MS).never()).
+                onTorchModeUnavailable(anyString());
+
+        // verify passing a null handler will raise IllegalArgumentException
+        try {
+            mCameraManager.registerTorchCallback(torchListener, null);
+            mCameraManager.unregisterTorchCallback(torchListener);
+            fail("should get IllegalArgumentException due to no handler");
+        } catch (IllegalArgumentException e) {
+            // expected exception
+        }
+    }
+
+    public void testCameraDeviceOpenAfterTorchOn() throws Exception {
+        if (mFlashCameraIdList.size() == 0)
+            return;
+
+        for (String id : mFlashCameraIdList) {
+            for (String idToOpen : mCameraIds) {
+                resetTorchModeStatus(id);
+
+                CameraManager.TorchCallback torchListener =
+                        mock(CameraManager.TorchCallback.class);
+
+                // this will trigger OFF for each id in mFlashCameraIdList
+                mCameraManager.registerTorchCallback(torchListener, mHandler);
+
+                // this will trigger ON for id
+                mCameraManager.setTorchMode(id, true);
+                SystemClock.sleep(TORCH_DURATION_MS);
+
+                // if id == idToOpen, this will trigger UNAVAILABLE and may trigger OFF.
+                // this may trigger UNAVAILABLE for any other id in mFlashCameraIdList
+                openDevice(idToOpen);
+
+                // if id == idToOpen, this will trigger OFF.
+                // this may trigger OFF for any other id in mFlashCameraIdList.
+                closeDevice(idToOpen);
+
+                // this may trigger OFF for id if not received previously.
+                mCameraManager.setTorchMode(id, false);
+
+                verify(torchListener, timeout(TORCH_TIMEOUT_MS).times(1)).
+                        onTorchModeChanged(id, true);
+                verify(torchListener, timeout(TORCH_TIMEOUT_MS).times(1)).
+                        onTorchModeChanged(anyString(), eq(true));
+
+                verify(torchListener, timeout(TORCH_TIMEOUT_MS).atLeast(2)).
+                        onTorchModeChanged(id, false);
+                verify(torchListener, atMost(3)).onTorchModeChanged(id, false);
+
+                verify(torchListener, timeout(TORCH_TIMEOUT_MS).
+                        atLeast(mFlashCameraIdList.size())).
+                        onTorchModeChanged(anyString(), eq(false));
+                verify(torchListener, atMost(mFlashCameraIdList.size() * 2 + 1)).
+                        onTorchModeChanged(anyString(), eq(false));
+
+                if (hasFlash(idToOpen)) {
+                    verify(torchListener, timeout(TORCH_TIMEOUT_MS).times(1)).
+                            onTorchModeUnavailable(idToOpen);
+                }
+                verify(torchListener, atMost(mFlashCameraIdList.size())).
+                            onTorchModeUnavailable(anyString());
+
+                mCameraManager.unregisterTorchCallback(torchListener);
+            }
+        }
+    }
+
+    public void testTorchModeExceptions() throws Exception {
+        // cameraIdsToTestTorch = all available camera ID + non-existing camera id +
+        //                        non-existing numeric camera id + null
+        String[] cameraIdsToTestTorch = new String[mCameraIds.length + 3];
+        System.arraycopy(mCameraIds, 0, cameraIdsToTestTorch, 0, mCameraIds.length);
+        cameraIdsToTestTorch[mCameraIds.length] = generateNonexistingCameraId();
+        cameraIdsToTestTorch[mCameraIds.length + 1] = generateNonexistingNumericCameraId();
+
+        for (String idToOpen : mCameraIds) {
+            openDevice(idToOpen);
+            try {
+                for (String id : cameraIdsToTestTorch) {
+                    try {
+                        mCameraManager.setTorchMode(id, true);
+                        SystemClock.sleep(TORCH_DURATION_MS);
+                        mCameraManager.setTorchMode(id, false);
+                        if (!hasFlash(id)) {
+                            fail("exception should be thrown when turning on torch mode of a " +
+                                    "camera without a flash");
+                        } else if (id.equals(idToOpen)) {
+                            fail("exception should be thrown when turning on torch mode of an " +
+                                    "opened camera");
+                        }
+                    } catch (CameraAccessException e) {
+                        if ((hasFlash(id) &&  id.equals(idToOpen) &&
+                                    e.getReason() == CameraAccessException.CAMERA_IN_USE) ||
+                            (hasFlash(id) && !id.equals(idToOpen) &&
+                                    e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE)) {
+                            continue;
+                        }
+                        fail("(" + id + ") not expecting: " + e.getMessage());
+                    } catch (IllegalArgumentException e) {
+                        if (hasFlash(id)) {
+                            fail("not expecting IllegalArgumentException");
+                        }
+                    }
+                }
+            } finally {
+                closeDevice(idToOpen);
+            }
+        }
+    }
+
+    private boolean hasFlash(String cameraId) {
+        return mFlashCameraIdList.contains(cameraId);
+    }
+
+    // make sure the torch status is off.
+    private void resetTorchModeStatus(String cameraId) throws Exception {
+        TorchCallbackListener torchListener = new TorchCallbackListener(cameraId);
+
+        mCameraManager.registerTorchCallback(torchListener, mHandler);
+        mCameraManager.setTorchMode(cameraId, true);
+        mCameraManager.setTorchMode(cameraId, false);
+
+        torchListener.waitOnStatusChange(TorchCallbackListener.STATUS_ON);
+        torchListener.waitOnStatusChange(TorchCallbackListener.STATUS_OFF);
+
+        mCameraManager.unregisterTorchCallback(torchListener);
+    }
+
+    private String generateNonexistingCameraId() {
+        String nonExisting = "none_existing_camera";
+        for (String id : mCameraIds) {
+            if (Arrays.asList(mCameraIds).contains(nonExisting)) {
+                nonExisting += id;
+            } else {
+                break;
+            }
+        }
+        return nonExisting;
+    }
+
+    // return a non-existing and non-negative numeric camera id.
+    private String generateNonexistingNumericCameraId() {
+        int[] numericCameraIds = new int[mCameraIds.length];
+        int size = 0;
+
+        for (String cameraId : mCameraIds) {
+            try {
+                int value = Integer.parseInt(cameraId);
+                if (value >= 0) {
+                    numericCameraIds[size++] = value;
+                }
+            } catch (Throwable e) {
+                // do nothing if camera id isn't an integer
+            }
+        }
+
+        if (size == 0) {
+            return "0";
+        }
+
+        Arrays.sort(numericCameraIds, 0, size);
+        if (numericCameraIds[0] != 0) {
+            return "0";
+        }
+
+        for (int i = 0; i < size - 1; i++) {
+            if (numericCameraIds[i] + 1 < numericCameraIds[i + 1]) {
+                return String.valueOf(numericCameraIds[i] + 1);
+            }
+        }
+
+        if (numericCameraIds[size - 1] != Integer.MAX_VALUE) {
+            return String.valueOf(numericCameraIds[size - 1] + 1);
+        }
+
+        fail("cannot find a non-existing and non-negative numeric camera id");
+        return null;
+    }
+
+    private final class TorchCallbackListener extends CameraManager.TorchCallback {
+        private static final String TAG = "TorchCallbackListener";
+        private static final int STATUS_WAIT_TIMEOUT_MS = 3000;
+        private static final int QUEUE_CAPACITY = 100;
+
+        private String mCameraId;
+        private ArrayBlockingQueue<Integer> mStatusQueue =
+                new ArrayBlockingQueue<Integer>(QUEUE_CAPACITY);
+
+        public static final int STATUS_UNAVAILABLE = 0;
+        public static final int STATUS_OFF = 1;
+        public static final int STATUS_ON = 2;
+
+        public TorchCallbackListener(String cameraId) {
+            // only care about events for this camera id.
+            mCameraId = cameraId;
+        }
+
+        public void waitOnStatusChange(int status) throws Exception {
+            while (true) {
+                Integer s = mStatusQueue.poll(STATUS_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+                if (s == null) {
+                    fail("waiting for status " + status + " timed out");
+                } else if (s.intValue() == status) {
+                    return;
+                }
+            }
+        }
+
+        @Override
+        public void onTorchModeUnavailable(String cameraId) {
+            if (cameraId.equals(mCameraId)) {
+                Integer s = new Integer(STATUS_UNAVAILABLE);
+                try {
+                    mStatusQueue.put(s);
+                } catch (Throwable e) {
+                    fail(e.getMessage());
+                }
+            }
+        }
+
+        @Override
+        public void onTorchModeChanged(String cameraId, boolean enabled) {
+            if (cameraId.equals(mCameraId)) {
+                Integer s;
+                if (enabled) {
+                    s = new Integer(STATUS_ON);
+                } else {
+                    s = new Integer(STATUS_OFF);
+                }
+                try {
+                    mStatusQueue.put(s);
+                } catch (Throwable e) {
+                    fail(e.getMessage());
+                }
+            }
+        }
+    }
+}
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 a410775..259e0e0 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -553,7 +553,8 @@
                 List<Surface> outputSurfaces = new ArrayList<Surface>();
                 outputSurfaces.add(yuvSurface);
                 outputSurfaces.add(captureSurface);
-                CaptureRequest.Builder request = prepareCaptureRequestForSurfaces(outputSurfaces);
+                CaptureRequest.Builder request = prepareCaptureRequestForSurfaces(outputSurfaces,
+                        CameraDevice.TEMPLATE_PREVIEW);
                 SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
 
                 for (int i = 0; i < NUM_SINGLE_CAPTURE_TESTED; i++) {
@@ -729,28 +730,6 @@
         }
     }
 
-    private CaptureRequest prepareCaptureRequest() throws Exception {
-        List<Surface> outputSurfaces = new ArrayList<Surface>();
-        Surface surface = mReader.getSurface();
-        assertNotNull("Fail to get surface from ImageReader", surface);
-        outputSurfaces.add(surface);
-        return prepareCaptureRequestForSurfaces(outputSurfaces).build();
-    }
-
-    private CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces)
-            throws Exception {
-        createSession(surfaces);
-
-        CaptureRequest.Builder captureBuilder =
-                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
-        assertNotNull("Fail to get captureRequest", captureBuilder);
-        for (Surface surface : surfaces) {
-            captureBuilder.addTarget(surface);
-        }
-
-        return captureBuilder;
-    }
-
     private void validateImage(Size sz, int format, int captureCount,  boolean repeating)
             throws Exception {
         // TODO: Add more format here, and wrap each one as a function.
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java
new file mode 100644
index 0000000..36a3f80
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.cts;
+
+import static android.hardware.camera2.cts.CameraTestUtils.*;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
+import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.media.Image;
+import android.media.ImageReader;
+import android.media.ImageWriter;
+import android.os.ConditionVariable;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * <p>
+ * Basic test for ImageWriter APIs. ImageWriter takes the images produced by
+ * camera (via ImageReader), then the data is consumed by either camera input
+ * interface or ImageReader.
+ * </p>
+ */
+public class ImageWriterTest extends Camera2AndroidTestCase {
+    private static final String TAG = "ImageWriterTest";
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    // Max number of images can be accessed simultaneously from ImageReader.
+    private static final int MAX_NUM_IMAGES = 3;
+    private static final int CAMERA_OPAQUE_FORMAT = ImageFormat.PRIVATE;
+    private ImageReader mReaderForWriter;
+    private ImageWriter mWriter;
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            closeImageReader(mReaderForWriter);
+        } finally {
+            mReaderForWriter = null;
+            if (mWriter != null) {
+                mWriter.close();
+                mWriter = null;
+            }
+        }
+
+        super.tearDown();
+    }
+
+    /**
+     * `
+     * <p>
+     * Basic YUV420_888 format ImageWriter ImageReader test that checks the
+     * images produced by camera can be passed correctly by ImageWriter.
+     * </p>
+     * <p>
+     * {@link ImageReader} reads the images produced by {@link CameraDevice}.
+     * The images are then passed to ImageWriter, which produces new images that
+     * are consumed by the second image reader. The images from first
+     * ImageReader should be identical with the images from the second
+     * ImageReader. This validates the basic image input interface of the
+     * ImageWriter. Below is the data path tested:
+     * <li>Explicit data copy: Dequeue an image from ImageWriter, copy the image
+     * data from first ImageReader into this image, then queue this image back
+     * to ImageWriter. This validates the ImageWriter explicit buffer copy
+     * interface.</li>
+     * </p>
+     */
+    public void testYuvImageWriterReaderOperation() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.i(TAG, "Testing Camera " + id);
+                openDevice(id);
+                readerWriterFormatTestByCamera(ImageFormat.YUV_420_888);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Basic Opaque format ImageWriter ImageReader test that checks the images
+     * produced by camera can be passed correctly by ImageWriter.
+     * </p>
+     * <p>
+     * {@link ImageReader} reads the images produced by {@link CameraDevice}.
+     * The images are then passed to ImageWriter, which produces new images that
+     * are consumed by the second image reader. The images from first
+     * ImageReader should be identical with the images from the second
+     * ImageReader. This validates the basic image input interface of the
+     * ImageWriter. Because opaque image is inaccessible by client, this test
+     * only covers below path, and only the image info is validated.
+     * <li>Direct image input to ImageWriter. The image from first ImageReader
+     * is directly injected into ImageWriter without needing to dequeue an input
+     * image. ImageWriter will migrate this opaque image into the destination
+     * surface without any data copy.</li>
+     * </p>
+     */
+    public void testOpaqueImageWriterReaderOperation() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.i(TAG, "Testing Camera " + id);
+                openDevice(id);
+                readerWriterFormatTestByCamera(CAMERA_OPAQUE_FORMAT);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    private final class SimpleImageWriterListener implements ImageWriter.ImageListener {
+        private final ConditionVariable imageReleased = new ConditionVariable();
+        @Override
+        public void onInputImageReleased(ImageWriter writer) {
+            if (writer != mWriter) {
+                return;
+            }
+
+            if (VERBOSE) Log.v(TAG, "Input image is released");
+            imageReleased.open();
+        }
+
+        public void waitForImageReleassed(long timeoutMs) {
+            if (imageReleased.block(timeoutMs)) {
+                imageReleased.close();
+            } else {
+                fail("wait for image available timed out after " + timeoutMs + "ms");
+            }
+        }
+    }
+
+    private void readerWriterFormatTestByCamera(int format)  throws Exception {
+        List<Size> sizes = getSortedSizesForFormat(mCamera.getId(), mCameraManager, format, null);
+        Size maxSize = sizes.get(0);
+        if (VERBOSE) {
+            Log.v(TAG, "Testing size " + maxSize);
+        }
+
+        // Create ImageReader for camera output.
+        SimpleImageReaderListener listenerForCamera  = new SimpleImageReaderListener();
+        createDefaultImageReader(maxSize, format, MAX_NUM_IMAGES, listenerForCamera);
+        if (VERBOSE) {
+            Log.v(TAG, "Created camera output ImageReader");
+        }
+
+        // Create ImageReader for ImageWriter output
+        SimpleImageReaderListener listenerForWriter  = new SimpleImageReaderListener();
+        mReaderForWriter = createImageReader(maxSize, format, MAX_NUM_IMAGES, listenerForWriter);
+        if (VERBOSE) {
+            Log.v(TAG, "Created ImageWriter output ImageReader");
+        }
+
+        // Create ImageWriter
+        Surface surface = mReaderForWriter.getSurface();
+        assertNotNull("Surface from ImageReader shouldn't be null", surface);
+        mWriter = ImageWriter.newInstance(surface, MAX_NUM_IMAGES);
+        SimpleImageWriterListener writerImageListener = new SimpleImageWriterListener();
+        mWriter.setImageListener(writerImageListener, mHandler);
+
+        // Start capture: capture 2 images.
+        List<Surface> outputSurfaces = new ArrayList<Surface>();
+        outputSurfaces.add(mReader.getSurface());
+        CaptureRequest.Builder requestBuilder = prepareCaptureRequestForSurfaces(outputSurfaces,
+                CameraDevice.TEMPLATE_PREVIEW);
+        SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
+        // Capture 1st image.
+        startCapture(requestBuilder.build(), /*repeating*/false, captureListener, mHandler);
+        // Capture 2nd image.
+        startCapture(requestBuilder.build(), /*repeating*/false, captureListener, mHandler);
+        if (VERBOSE) {
+            Log.v(TAG, "Submitted 2 captures");
+        }
+
+        // Image from the first ImageReader.
+        Image cameraImage = null;
+        // ImageWriter input image.
+        Image inputImage = null;
+        // Image from the second ImageReader.
+        Image outputImage = null;
+        if (format == CAMERA_OPAQUE_FORMAT) {
+            assertTrue("First ImageReader should be opaque",
+                    mReader.isOpaque());
+            assertTrue("Second ImageReader should be opaque",
+                    mReaderForWriter.isOpaque());
+            assertTrue("Format of first ImageReader should be opaque",
+                    mReader.getImageFormat() == CAMERA_OPAQUE_FORMAT);
+            assertTrue(" Format of second ImageReader should be opaque",
+                    mReaderForWriter.getImageFormat() == CAMERA_OPAQUE_FORMAT);
+            assertTrue(" Format of ImageWriter should be opaque",
+                    mWriter.getFormat() == CAMERA_OPAQUE_FORMAT);
+
+            // Validate 2 images
+            validateOpaqueImages(maxSize, listenerForCamera, listenerForWriter, captureListener,
+                    /*numImages*/2, writerImageListener);
+        } else {
+            // Test case 1: Explicit data copy, only applicable for explicit formats.
+
+            // Get 1st image from first ImageReader, and copy the data to ImageWrtier input image
+            cameraImage = listenerForCamera.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+            inputImage = mWriter.dequeueInputImage();
+            inputImage.setTimestamp(cameraImage.getTimestamp());
+            if (VERBOSE) {
+                Log.v(TAG, "Image is being copied");
+            }
+            imageCopy(cameraImage, inputImage);
+            if (VERBOSE) {
+                Log.v(TAG, "Image copy is done");
+            }
+            mCollector.expectTrue(
+                    "ImageWriter 1st input image should match camera 1st output image",
+                    isImageStronglyEqual(inputImage, cameraImage));
+
+            mWriter.queueInputImage(inputImage);
+            outputImage = listenerForWriter.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+
+            mCollector.expectTrue("ImageWriter 1st output image should match 1st input image",
+                    isImageStronglyEqual(cameraImage, outputImage));
+            if (DEBUG) {
+                String img1FileName = DEBUG_FILE_NAME_BASE + "/" + maxSize + "_image1_copy.yuv";
+                String outputImg1FileName = DEBUG_FILE_NAME_BASE + "/" + maxSize
+                        + "_outputImage2_copy.yuv";
+                dumpFile(img1FileName, getDataFromImage(cameraImage));
+                dumpFile(outputImg1FileName, getDataFromImage(outputImage));
+            }
+            // No need to close inputImage, as it is sent to the surface after queueInputImage;
+            cameraImage.close();
+            outputImage.close();
+
+            // Make sure ImageWriter listener callback is fired.
+            writerImageListener.waitForImageReleassed(CAPTURE_IMAGE_TIMEOUT_MS);
+
+            // Test case 2: Directly inject the image into ImageWriter: works for all formats.
+
+            // Get 2nd image and queue it directly to ImageWrier
+            cameraImage = listenerForCamera.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+            // make a copy of image1 data, as it will be closed after queueInputImage;
+            byte[] img1Data = getDataFromImage(cameraImage);
+            if (DEBUG) {
+                String img2FileName = DEBUG_FILE_NAME_BASE + "/" + maxSize + "_image2.yuv";
+                dumpFile(img2FileName, img1Data);
+            }
+            mWriter.queueInputImage(cameraImage);
+            outputImage = listenerForWriter.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+            byte[] outputImageData = getDataFromImage(outputImage);
+
+            mCollector.expectTrue("ImageWriter 2nd output image should match camera "
+                    + "2nd output image", Arrays.equals(img1Data, outputImageData));
+
+            if (DEBUG) {
+                String outputImgFileName = DEBUG_FILE_NAME_BASE + "/" + maxSize +
+                        "_outputImage2.yuv";
+                dumpFile(outputImgFileName, outputImageData);
+            }
+            // No need to close inputImage, as it is sent to the surface after queueInputImage;
+            outputImage.close();
+
+            // Make sure ImageWriter listener callback is fired.
+            writerImageListener.waitForImageReleassed(CAPTURE_IMAGE_TIMEOUT_MS);
+        }
+
+        stopCapture(/*fast*/false);
+        mReader.close();
+        mReader = null;
+        mReaderForWriter.close();
+        mReaderForWriter = null;
+        mWriter.close();
+        mWriter = null;
+    }
+
+    private void validateOpaqueImages(Size maxSize, SimpleImageReaderListener listenerForCamera,
+            SimpleImageReaderListener listenerForWriter, SimpleCaptureCallback captureListener,
+            int numImages, SimpleImageWriterListener writerListener) throws Exception {
+        Image cameraImage;
+        Image outputImage;
+        for (int i = 0; i < numImages; i++) {
+            cameraImage = listenerForCamera.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+            CaptureResult result = captureListener.getCaptureResult(CAPTURE_IMAGE_TIMEOUT_MS);
+            validateOpaqueImage(cameraImage, "Opaque image " + i + "from camera: ", maxSize,
+                    result);
+            mWriter.queueInputImage(cameraImage);
+            outputImage = listenerForWriter.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+            validateOpaqueImage(outputImage, "First Opaque image output by ImageWriter: ",
+                    maxSize, result);
+            outputImage.close();
+            writerListener.waitForImageReleassed(CAPTURE_IMAGE_TIMEOUT_MS);
+        }
+    }
+
+    private void validateOpaqueImage(Image image, String msg, Size imageSize,
+            CaptureResult result) {
+        assertNotNull("Opaque image Capture result should not be null", result != null);
+        mCollector.expectTrue(msg + "Opaque image format should be: " + CAMERA_OPAQUE_FORMAT,
+                image.getFormat() == CAMERA_OPAQUE_FORMAT);
+        mCollector.expectTrue(msg + "Opaque image format should be: " + CAMERA_OPAQUE_FORMAT,
+                image.getFormat() == CAMERA_OPAQUE_FORMAT);
+        mCollector.expectTrue(msg + "Opaque image number planes should be zero",
+                image.getPlanes().length == 0);
+        mCollector.expectTrue(msg + "Opaque image size should be " + imageSize,
+                image.getWidth() == imageSize.getWidth() &&
+                image.getHeight() == imageSize.getHeight());
+        long timestampNs = result.get(CaptureResult.SENSOR_TIMESTAMP);
+        mCollector.expectTrue(msg + "Opaque image timestamp should be " + timestampNs,
+                image.getTimestamp() == timestampNs);
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
index b8c2f2e..3076d09 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -268,12 +268,10 @@
                 capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE";
                 requestKeys.add(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE);
                 requestKeys.add(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION);
-                requestKeys.add(CaptureRequest.CONTROL_AE_LOCK);
                 requestKeys.add(CaptureRequest.CONTROL_AE_MODE);
                 requestKeys.add(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
                 requestKeys.add(CaptureRequest.CONTROL_AF_MODE);
                 requestKeys.add(CaptureRequest.CONTROL_AF_TRIGGER);
-                requestKeys.add(CaptureRequest.CONTROL_AWB_LOCK);
                 requestKeys.add(CaptureRequest.CONTROL_AWB_MODE);
                 requestKeys.add(CaptureRequest.CONTROL_CAPTURE_INTENT);
                 requestKeys.add(CaptureRequest.CONTROL_EFFECT_MODE);
@@ -319,6 +317,7 @@
                 requestKeys.add(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE);
                 requestKeys.add(CaptureRequest.TONEMAP_CURVE);
                 requestKeys.add(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
+                requestKeys.add(CaptureRequest.CONTROL_AWB_LOCK);
 
                 // Legacy mode always doesn't support these requirements
                 Boolean contrastCurveModeSupported = false;
@@ -342,9 +341,12 @@
                         "Tonemap mode must include CONTRAST_CURVE", contrastCurveModeSupported));
                 additionalRequirements.add(new Pair<String, Boolean>(
                         "Color aberration mode must include OFF", offColorAberrationModeSupported));
+                additionalRequirements.add(new Pair<String, Boolean>(
+                        "Must support AWB lock", mStaticInfo.isAwbLockSupported()));
                 break;
             case REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
                 capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR";
+                requestKeys.add(CaptureRequest.CONTROL_AE_LOCK);
                 requestKeys.add(CaptureRequest.SENSOR_FRAME_DURATION);
                 requestKeys.add(CaptureRequest.SENSOR_EXPOSURE_TIME);
                 requestKeys.add(CaptureRequest.SENSOR_SENSITIVITY);
@@ -355,6 +357,8 @@
                     requestKeys.add(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE);
                 }
                 requestKeys.add(CaptureRequest.BLACK_LEVEL_LOCK);
+                additionalRequirements.add(new Pair<String, Boolean>(
+                        "Must support AE lock", mStaticInfo.isAeLockSupported()));
                 break;
             case REQUEST_AVAILABLE_CAPABILITIES_RAW:
                 // RAW_CAPABILITY needs to check for not just capture request keys
@@ -374,6 +378,11 @@
                     resultKeys.add(CaptureResult.LENS_FILTER_DENSITY);
                 }
                 break;
+
+            case REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
+            case REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING:
+                // Tested in ExtendedCameraCharacteristicsTest
+                return;
             default:
                 capabilityName = "Unknown";
                 assertTrue(String.format("Unknown capability set: %d", capability),
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 2554b17..c3cf8d0 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -426,6 +426,10 @@
         waitForNumResults(resultListener, NUM_FRAMES_WAITED);
 
         stopPreview();
+
+        // Free image resources
+        image.close();
+        closeImageReader();
         return;
     }
 
@@ -519,7 +523,10 @@
             // LEGACY Devices don't have the AWB_STATE reported in results, so just wait
             waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
         }
-        previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
+        boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
+        if (canSetAwbLock) {
+            previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
+        }
         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
         // Validate the next result immediately for region and mode.
         result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
@@ -595,6 +602,9 @@
         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
         validateJpegCapture(image, maxStillSz);
 
+        // Free image resources
+        image.close();
+
         stopPreview();
     }
 
@@ -641,6 +651,10 @@
                 Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ?
                         RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS);
                 validateJpegCapture(image, stillSz);
+
+                // Free image resources
+                image.close();
+
                 // stopPreview must be called here to make sure next time a preview stream
                 // is created with new size.
                 stopPreview();
@@ -691,6 +705,9 @@
             dumpFile(rawFileName, rawBuffer);
         }
 
+        // Free image resources
+        image.close();
+
         stopPreview();
     }
 
@@ -986,9 +1003,23 @@
             }
 
             // Validate capture result vs. request
+            Size resultThumbnailSize = stillResult.get(CaptureResult.JPEG_THUMBNAIL_SIZE);
+            int orientationTested = EXIF_TEST_DATA[i].jpegOrientation;
+            if ((orientationTested == 90 || orientationTested == 270)) {
+                int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
+                        /*defaultValue*/-1);
+                if (exifOrientation == ExifInterface.ORIENTATION_UNDEFINED) {
+                    // Device physically rotated image+thumbnail data
+                    // Expect thumbnail size to be also rotated
+                    resultThumbnailSize = new Size(
+                            resultThumbnailSize.getHeight(),
+                            resultThumbnailSize.getWidth());
+                }
+            }
+
             mCollector.expectEquals("JPEG thumbnail size result and request should match",
                     testThumbnailSizes[i],
-                    stillResult.get(CaptureResult.JPEG_THUMBNAIL_SIZE));
+                    resultThumbnailSize);
             if (mCollector.expectKeyValueNotNull(stillResult, CaptureResult.JPEG_GPS_LOCATION) !=
                     null) {
                 mCollector.expectTrue("GPS location result and request should match.",
@@ -1008,6 +1039,9 @@
             if (!mStaticInfo.isHardwareLevelLegacy()) {
                 jpegTestExifExtraTags(exif, maxStillSz, stillResult);
             }
+
+            // Free image resources
+            image.close();
         }
     }
 
@@ -1250,7 +1284,12 @@
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
         CaptureRequest.Builder stillRequest =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
-        stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+        boolean canSetAeLock = mStaticInfo.isAeLockSupported();
+
+        if (canSetAeLock) {
+            stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+        }
+
         CaptureResult normalResult;
         CaptureResult compensatedResult;
 
@@ -1260,7 +1299,7 @@
         long maxExposureValuePreview = -1;
         long maxExposureValueStill = -1;
         if (mStaticInfo.isCapabilitySupported(
-                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
             // Minimum exposure settings is mostly static while maximum exposure setting depends on
             // frame rate range which in term depends on capture request.
             minExposureValue = mStaticInfo.getSensitivityMinimumOrDefault() *
@@ -1288,7 +1327,7 @@
 
             long normalExposureValue = -1;
             if (mStaticInfo.isCapabilitySupported(
-                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
                 // get and check if current exposure value is valid
                 normalExposureValue = getExposureValue(normalResult);
                 mCollector.expectInRange("Exposure setting out of bound", normalExposureValue,
@@ -1312,9 +1351,15 @@
             // frames to go back to locked state
             previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
                     exposureCompensation);
-            previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+            if (canSetAeLock) {
+                previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+            }
             mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
-            waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+            if (canSetAeLock) {
+                waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+            } else {
+                waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+            }
 
             // Issue still capture
             if (VERBOSE) {
@@ -1330,7 +1375,7 @@
                     request, WAIT_FOR_RESULT_TIMEOUT_MS);
 
             if (mStaticInfo.isCapabilitySupported(
-                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
                 // Verify the exposure value compensates as requested
                 long compensatedExposureValue = getExposureValue(compensatedResult);
                 mCollector.expectInRange("Exposure setting out of bound", compensatedExposureValue,
@@ -1357,8 +1402,10 @@
             mCollector.expectEquals("Exposure compensation result should match requested value.",
                     exposureCompensation,
                     compensatedResult.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION));
-            mCollector.expectTrue("Exposure lock should be set",
-                    compensatedResult.get(CaptureResult.CONTROL_AE_LOCK));
+            if (canSetAeLock) {
+                mCollector.expectTrue("Exposure lock should be set",
+                        compensatedResult.get(CaptureResult.CONTROL_AE_LOCK));
+            }
 
             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
             validateJpegCapture(image, maxStillSz);
@@ -1366,7 +1413,9 @@
 
             // Recover AE compensation and lock
             previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
-            previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false);
+            if (canSetAeLock) {
+                previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false);
+            }
             mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
         }
     }
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 2a654db3..6fc78dd 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
@@ -586,6 +586,17 @@
             checkTrueForKey(key, "Full-capability camera devices must support FAST mode",
                     modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST));
         }
+
+        if (isHardwareLevelLimitedOrBetter()) {
+            // FAST and HIGH_QUALITY mode must be both present or both not present
+            List<Integer> coupledModes = Arrays.asList(new Integer[] {
+                    CameraMetadata.HOT_PIXEL_MODE_FAST,
+                    CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY
+            });
+            checkTrueForKey(
+                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
+                    containsAllOrNone(modeList, coupledModes));
+        }
         checkElementDistinct(key, modeList);
         checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF,
                 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY);
@@ -673,6 +684,17 @@
                     modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) &&
                     modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
         }
+
+        if (isHardwareLevelLimitedOrBetter()) {
+            // FAST and HIGH_QUALITY mode must be both present or both not present
+            List<Integer> coupledModes = Arrays.asList(new Integer[] {
+                    CameraMetadata.TONEMAP_MODE_FAST,
+                    CameraMetadata.TONEMAP_MODE_HIGH_QUALITY
+            });
+            checkTrueForKey(
+                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
+                    containsAllOrNone(modeList, coupledModes));
+        }
         checkElementDistinct(key, modeList);
         checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE,
                 CameraMetadata.TONEMAP_MODE_HIGH_QUALITY);
@@ -1239,14 +1261,25 @@
             return new int[0];
         }
 
+        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
         // Full device should always include OFF and FAST
         if (isHardwareLevelFull()) {
-            List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
             checkTrueForKey(key, "Full device must contain OFF and FAST edge modes",
                     modeList.contains(CameraMetadata.EDGE_MODE_OFF) &&
                     modeList.contains(CameraMetadata.EDGE_MODE_FAST));
         }
 
+        if (isHardwareLevelLimitedOrBetter()) {
+            // FAST and HIGH_QUALITY mode must be both present or both not present
+            List<Integer> coupledModes = Arrays.asList(new Integer[] {
+                    CameraMetadata.EDGE_MODE_FAST,
+                    CameraMetadata.EDGE_MODE_HIGH_QUALITY
+            });
+            checkTrueForKey(
+                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
+                    containsAllOrNone(modeList, coupledModes));
+        }
+
         return edgeModes;
     }
 
@@ -1259,14 +1292,25 @@
             return new int[0];
         }
 
+        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
         // Full device should always include OFF and FAST
         if (isHardwareLevelFull()) {
-            List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
+
             checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes",
                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) &&
                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST));
         }
 
+        if (isHardwareLevelLimitedOrBetter()) {
+            // FAST and HIGH_QUALITY mode must be both present or both not present
+            List<Integer> coupledModes = Arrays.asList(new Integer[] {
+                    CameraMetadata.NOISE_REDUCTION_MODE_FAST,
+                    CameraMetadata.NOISE_REDUCTION_MODE_HIGH_QUALITY
+            });
+            checkTrueForKey(
+                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
+                    containsAllOrNone(modeList, coupledModes));
+        }
         return noiseReductionModes;
     }
 
@@ -1444,6 +1488,17 @@
         checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode",
                 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) ||
                 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST));
+
+        if (isHardwareLevelLimitedOrBetter()) {
+            // FAST and HIGH_QUALITY mode must be both present or both not present
+            List<Integer> coupledModes = Arrays.asList(new Integer[] {
+                    CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST,
+                    CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY
+            });
+            checkTrueForKey(
+                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
+                    containsAllOrNone(modeList, coupledModes));
+        }
         checkElementDistinct(key, modeList);
         checkArrayValuesInRange(key, modes,
                 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF,
@@ -1618,6 +1673,25 @@
     }
 
     /*
+     * Determine if camera device support AE lock control
+     *
+     * @return {@code true} if AE lock control is supported
+     */
+    public boolean isAeLockSupported() {
+        return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
+    }
+
+    /*
+     * Determine if camera device support AWB lock control
+     *
+     * @return {@code true} if AWB lock control is supported
+     */
+    public boolean isAwbLockSupported() {
+        return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
+    }
+
+
+    /*
      * Determine if camera device support manual lens shading map control
      *
      * @return {@code true} if manual lens shading map control is supported
@@ -1928,6 +2002,19 @@
         }
     }
 
+    /* Helper function to check if the coupled modes are either all present or all non-present */
+    private <T> boolean containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes) {
+        if (observedModes.containsAll(coupledModes)) {
+            return true;
+        }
+        for (T mode : coupledModes) {
+            if (observedModes.contains(mode)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private <T> void failKeyCheck(Key<T> key, String message) {
         // TODO: Consider only warning once per key/message combination if it's too spammy.
         // TODO: Consider offering other options such as throwing an assertion exception
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 5fc6321..bff08db 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
@@ -20,6 +20,7 @@
 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
 
 import android.content.Context;
+import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
 import android.hardware.camera2.CameraDevice;
@@ -42,6 +43,7 @@
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class Camera2AndroidTestCase extends AndroidTestCase {
@@ -288,8 +290,15 @@
     protected ImageReader createImageReader(Size size, int format, int maxNumImages,
             ImageReader.OnImageAvailableListener listener) throws Exception {
 
-        ImageReader reader = ImageReader.newInstance(size.getWidth(), size.getHeight(),
-                format, maxNumImages);
+        ImageReader reader = null;
+        if (format == ImageFormat.PRIVATE) {
+            // Create opaque ImageReader
+            reader = ImageReader.newOpaqueInstance(size.getWidth(), size.getHeight(), maxNumImages);
+        } else {
+            reader = ImageReader.newInstance(size.getWidth(), size.getHeight(),
+                    format, maxNumImages);
+        }
+
         reader.setOnImageAvailableListener(listener, mHandler);
         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
         return reader;
@@ -323,4 +332,28 @@
             }
         }
     }
+
+    protected CaptureRequest prepareCaptureRequest() throws Exception {
+        List<Surface> outputSurfaces = new ArrayList<Surface>();
+        Surface surface = mReader.getSurface();
+        assertNotNull("Fail to get surface from ImageReader", surface);
+        outputSurfaces.add(surface);
+        return prepareCaptureRequestForSurfaces(outputSurfaces, CameraDevice.TEMPLATE_PREVIEW)
+                .build();
+    }
+
+    protected CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces,
+            int template)
+            throws Exception {
+        createSession(surfaces);
+
+        CaptureRequest.Builder captureBuilder =
+                mCamera.createCaptureRequest(template);
+        assertNotNull("Fail to get captureRequest", captureBuilder);
+        for (Surface surface : surfaces) {
+            captureBuilder.addTarget(surface);
+        }
+
+        return captureBuilder;
+    }
 }
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index 77d4bb7f..43e3e89 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -49,7 +49,7 @@
 
 # uncomment when b/13249737 is fixed
 #LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
+LOCAL_JAVA_LIBRARIES += android.test.runner org.apache.http.legacy
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index d53b2c6..e913f05 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -28,6 +28,7 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
 
         <activity android:name="android.media.cts.AudioManagerStub"
             android:label="AudioManagerStub"/>
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 67473e1..dbb609d 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -1310,13 +1310,11 @@
 
             /* test if the explicitly named codec is present on the system */
             if (explicitCodecName != null) {
-                try {
-                    MediaCodec codec = MediaCodec.createByCodecName(explicitCodecName);
-                    if (codec != null) {
-                        codec.release();
-                        add(new Codec(explicitCodecName, null, mediaList));
-                    }
-                } catch (Exception e) {}
+                MediaCodec codec = MediaCodec.createByCodecName(explicitCodecName);
+                if (codec != null) {
+                    codec.release();
+                    add(new Codec(explicitCodecName, null, mediaList));
+                }
             }
         } catch (Throwable t) {
             Log.wtf("Constructor failed", t);
diff --git a/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java b/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java
index 08e1d67..9272d58 100644
--- a/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.media.AsyncPlayer;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.provider.Settings;
@@ -34,4 +35,13 @@
         asyncPlayer.stop();
     }
 
+    public void testAsyncPlayerAudioAttributes() throws Exception {
+        final Uri PLAY_URI = Settings.System.DEFAULT_NOTIFICATION_URI;
+        AsyncPlayer asyncPlayer = new AsyncPlayer(null);
+        asyncPlayer.play(getContext(), PLAY_URI, true,
+                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
+        final int PLAY_TIME = 3000;
+        Thread.sleep(PLAY_TIME);
+        asyncPlayer.stop();
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/AudioEffectTest.java b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
index 1c96abd..dce7680 100644
--- a/tests/tests/media/src/android/media/cts/AudioEffectTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
@@ -65,9 +65,6 @@
 
     //Test case 0.0: test queryEffects() and platfrom at least provides an Equalizer
     public void test0_0QueryEffects() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
 
         AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
 
@@ -125,9 +122,6 @@
 
     //Test case 1.3: test getEnabled() failure when called on released effect
     public void test1_3GetEnabledAfterRelease() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         try {
             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
                     AudioEffect.EFFECT_TYPE_NULL,
@@ -150,9 +144,6 @@
 
     //Test case 1.4: test contructor on mediaPlayer audio session
     public void test1_4InsertOnMediaPlayer() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         MediaPlayer mp = new MediaPlayer();
         assertNotNull("could not create mediaplayer", mp);
         AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
@@ -285,9 +276,6 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         try {
             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
                     AudioEffect.EFFECT_TYPE_NULL,
@@ -315,9 +303,6 @@
 
     //Test case 2.1: test setEnabled() throws exception after release
     public void test2_1SetEnabledAfterRelease() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         try {
             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
                     AudioEffect.EFFECT_TYPE_NULL,
@@ -649,9 +634,6 @@
 
     //Test case 4.0: test control passed to higher priority client
     public void test4_0setEnabledLowerPriority() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         AudioEffect effect1 = null;
         AudioEffect effect2 = null;
         try {
diff --git a/tests/tests/media/src/android/media/cts/AudioHelper.java b/tests/tests/media/src/android/media/cts/AudioHelper.java
new file mode 100644
index 0000000..833c235
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/AudioHelper.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import java.nio.ByteBuffer;
+import org.junit.Assert;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.AudioTrack;
+import android.os.Looper;
+
+// Used for statistics and loopers in listener tests.
+// See AudioRecordTest.java and AudioTrack_ListenerTest.java.
+public class AudioHelper {
+    public static class Statistics {
+        public void add(double value) {
+            final double absValue = Math.abs(value);
+            mSum += value;
+            mSumAbs += absValue;
+            mMaxAbs = Math.max(mMaxAbs, absValue);
+            ++mCount;
+        }
+
+        public double getAvg() {
+            if (mCount == 0) {
+                return 0;
+            }
+            return mSum / mCount;
+        }
+
+        public double getAvgAbs() {
+            if (mCount == 0) {
+                return 0;
+            }
+            return mSumAbs / mCount;
+        }
+
+        public double getMaxAbs() {
+            return mMaxAbs;
+        }
+
+        private int mCount = 0;
+        private double mSum = 0;
+        private double mSumAbs = 0;
+        private double mMaxAbs = 0;
+    }
+
+    // for listener tests
+    // lightweight java.util.concurrent.Future*
+    public static class FutureLatch<T>
+    {
+        private T mValue;
+        private boolean mSet;
+        public void set(T value)
+        {
+            synchronized (this) {
+                assert !mSet;
+                mValue = value;
+                mSet = true;
+                notify();
+            }
+        }
+        public T get()
+        {
+            T value;
+            synchronized (this) {
+                while (!mSet) {
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                        ;
+                    }
+                }
+                value = mValue;
+            }
+            return value;
+        }
+    }
+
+    // for listener tests
+    // represents a factory for T
+    public interface MakesSomething<T>
+    {
+        T makeSomething();
+    }
+
+    // for listener tests
+    // used to construct an object in the context of an asynchronous thread with looper
+    public static class MakeSomethingAsynchronouslyAndLoop<T>
+    {
+        private Thread mThread;
+        volatile private Looper mLooper;
+        private final MakesSomething<T> mWhatToMake;
+
+        public MakeSomethingAsynchronouslyAndLoop(MakesSomething<T> whatToMake)
+        {
+            assert whatToMake != null;
+            mWhatToMake = whatToMake;
+        }
+
+        public T make()
+        {
+            final FutureLatch<T> futureLatch = new FutureLatch<T>();
+            mThread = new Thread()
+            {
+                @Override
+                public void run()
+                {
+                    Looper.prepare();
+                    mLooper = Looper.myLooper();
+                    T something = mWhatToMake.makeSomething();
+                    futureLatch.set(something);
+                    Looper.loop();
+                }
+            };
+            mThread.start();
+            return futureLatch.get();
+        }
+        public void join()
+        {
+            mLooper.quit();
+            try {
+                mThread.join();
+            } catch (InterruptedException e) {
+                ;
+            }
+            // avoid dangling references
+            mLooper = null;
+            mThread = null;
+        }
+    }
+
+    public static int outChannelMaskFromInChannelMask(int channelMask) {
+        switch (channelMask) {
+            case AudioFormat.CHANNEL_IN_MONO:
+                return AudioFormat.CHANNEL_OUT_MONO;
+            case AudioFormat.CHANNEL_IN_STEREO:
+                return AudioFormat.CHANNEL_OUT_STEREO;
+            default:
+                return AudioFormat.CHANNEL_INVALID;
+        }
+    }
+
+    /* AudioRecordAudit extends AudioRecord to allow concurrent playback
+     * of read content to an AudioTrack.
+     * This affects AudioRecord timing.
+     */
+    public static class AudioRecordAudit extends AudioRecord {
+        AudioRecordAudit(int audioSource, int sampleRate, int channelMask,
+                int format, int bufferSize) {
+            this(audioSource, sampleRate, channelMask, format, bufferSize,
+                    AudioManager.STREAM_MUSIC, 1000 /*delayMs*/);
+        }
+
+        AudioRecordAudit(int audioSource, int sampleRate, int channelMask,
+                int format, int bufferSize, int auditStreamType, int delayMs) {
+            super(audioSource, sampleRate, channelMask, format, bufferSize);
+
+            if (delayMs >= 0) { // create an AudioTrack
+                final int channelOutMask = outChannelMaskFromInChannelMask(channelMask);
+                final int bufferOutFrames = sampleRate * delayMs / 1000;
+                final int bufferOutSamples = bufferOutFrames
+                        * AudioFormat.channelCountFromOutChannelMask(channelOutMask);
+                final int bufferOutSize = bufferOutSamples
+                        * AudioFormat.getBytesPerSample(format);
+
+                mTrack = new AudioTrack(auditStreamType, sampleRate, channelOutMask, format,
+                        bufferOutSize, AudioTrack.MODE_STREAM);
+                mPosition = 0;
+                mFinishAtMs = 0;
+            }
+        }
+
+        @Override
+        public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
+            // for byte array access we verify format is 8 bit PCM (typical use)
+            Assert.assertEquals(TAG + ": format mismatch",
+                    AudioFormat.ENCODING_PCM_8BIT, getAudioFormat());
+            int samples = super.read(audioData, offsetInBytes, sizeInBytes);
+            if (mTrack != null) {
+                Assert.assertEquals(samples, mTrack.write(audioData, offsetInBytes, samples));
+                mPosition += samples / mTrack.getChannelCount();
+            }
+            return samples;
+        }
+
+        @Override
+        public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
+            // for short array access we verify format is 16 bit PCM (typical use)
+            Assert.assertEquals(TAG + ": format mismatch",
+                    AudioFormat.ENCODING_PCM_16BIT, getAudioFormat());
+            int samples = super.read(audioData, offsetInShorts, sizeInShorts);
+            if (mTrack != null) {
+                Assert.assertEquals(samples, mTrack.write(audioData, offsetInShorts, samples));
+                mPosition += samples / mTrack.getChannelCount();
+            }
+            return samples;
+        }
+
+        @Override
+        public int read(float[] audioData, int offsetInFloats, int sizeInFloats, int readMode) {
+            // for float array access we verify format is float PCM (typical use)
+            Assert.assertEquals(TAG + ": format mismatch",
+                    AudioFormat.ENCODING_PCM_FLOAT, getAudioFormat());
+            int samples = super.read(audioData, offsetInFloats, sizeInFloats, readMode);
+            if (mTrack != null) {
+                Assert.assertEquals(samples, mTrack.write(audioData, offsetInFloats, samples,
+                        AudioTrack.WRITE_BLOCKING));
+                mPosition += samples / mTrack.getChannelCount();
+            }
+            return samples;
+        }
+
+        @Override
+        public int read(ByteBuffer audioBuffer, int sizeInBytes) {
+            int bytes = super.read(audioBuffer, sizeInBytes);
+            if (mTrack != null) {
+                // read does not affect position and limit of the audioBuffer.
+                // we make a duplicate to change that for writing to the output AudioTrack
+                // which does check position and limit.
+                ByteBuffer copy = audioBuffer.duplicate();
+                copy.position(0).limit(bytes);  // read places data at the start of the buffer.
+                Assert.assertEquals(bytes, mTrack.write(copy, bytes, AudioTrack.WRITE_BLOCKING));
+                mPosition += bytes /
+                        (mTrack.getChannelCount()
+                                * AudioFormat.getBytesPerSample(mTrack.getAudioFormat()));
+            }
+            return bytes;
+        }
+
+        @Override
+        public void startRecording() {
+            super.startRecording();
+            if (mTrack != null) {
+                mTrack.play();
+            }
+        }
+
+        @Override
+        public void stop() {
+            super.stop();
+            if (mTrack != null) {
+                if (mPosition > 0) { // stop may be called multiple times.
+                    final int remainingFrames = mPosition - mTrack.getPlaybackHeadPosition();
+                    mFinishAtMs = System.currentTimeMillis()
+                            + remainingFrames * 1000 / mTrack.getSampleRate();
+                    mPosition = 0;
+                }
+                mTrack.stop(); // allows remaining data to play out
+            }
+        }
+
+        @Override
+        public void release() {
+            super.release();
+            if (mTrack != null) {
+                final long remainingMs = mFinishAtMs - System.currentTimeMillis();
+                if (remainingMs > 0) {
+                    try {
+                        Thread.sleep(remainingMs);
+                    } catch (InterruptedException e) {
+                        ;
+                    }
+                }
+                mTrack.release();
+                mTrack = null;
+            }
+        }
+
+        public AudioTrack mTrack;
+        private final static String TAG = "AudioRecordAudit";
+        private int mPosition;
+        private long mFinishAtMs;
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index f58e6ab..ded0539 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -19,7 +19,6 @@
 import static android.media.AudioManager.ADJUST_LOWER;
 import static android.media.AudioManager.ADJUST_RAISE;
 import static android.media.AudioManager.ADJUST_SAME;
-import static android.media.AudioManager.FLAG_ALLOW_RINGER_MODES;
 import static android.media.AudioManager.MODE_IN_CALL;
 import static android.media.AudioManager.MODE_IN_COMMUNICATION;
 import static android.media.AudioManager.MODE_NORMAL;
@@ -45,7 +44,7 @@
 import android.media.MediaPlayer;
 import android.os.Vibrator;
 import android.provider.Settings;
-import android.telephony.TelephonyManager;
+import android.provider.Settings.System;
 import android.test.AndroidTestCase;
 import android.view.SoundEffectConstants;
 
@@ -57,10 +56,7 @@
     private final static long TIME_TO_PLAY = 2000;
     private AudioManager mAudioManager;
     private boolean mHasVibrator;
-    private boolean mUseMasterVolume;
     private boolean mUseFixedVolume;
-    private int[] mMasterVolumeRamp;
-    private TreeMap<Integer, Integer> mMasterVolumeMap = new TreeMap<Integer, Integer>();
     private boolean mIsTelevision;
 
     @Override
@@ -69,16 +65,8 @@
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = (vibrator != null) && vibrator.hasVibrator();
-        mUseMasterVolume = mContext.getResources().getBoolean(
-                Resources.getSystem().getIdentifier("config_useMasterVolume", "bool", "android"));
         mUseFixedVolume = mContext.getResources().getBoolean(
                 Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
-        mMasterVolumeRamp = mContext.getResources().getIntArray(
-                Resources.getSystem().getIdentifier("config_masterVolumeRamp", "array", "android"));
-        assertTrue((mMasterVolumeRamp.length > 0) && (mMasterVolumeRamp.length % 2 == 0));
-        for (int i = 0; i < mMasterVolumeRamp.length; i+=2) {
-            mMasterVolumeMap.put(mMasterVolumeRamp[i], mMasterVolumeRamp[i+1]);
-        }
         PackageManager packageManager = mContext.getPackageManager();
         mIsTelevision = packageManager != null
                 && (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
@@ -350,6 +338,12 @@
             mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
 
             int maxVolume = mAudioManager.getStreamMaxVolume(streams[i]);
+            int minVolume = mAudioManager.getStreamMinVolume(streams[i]);
+
+            // validate min
+            assertTrue(String.format("minVolume(%d) must be >= 0", minVolume), minVolume >= 0);
+            assertTrue(String.format("minVolume(%d) must be < maxVolume(%d)", minVolume, maxVolume),
+                    minVolume < maxVolume);
 
             mAudioManager.setStreamVolume(streams[i], 1, 0);
             if (mUseFixedVolume) {
@@ -384,7 +378,7 @@
             // volume lower
             mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
             volume = mAudioManager.getStreamVolume(streams[i]);
-            while (volume > 0) {
+            while (volume > minVolume) {
                 volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
                 mAudioManager.adjustStreamVolume(streams[i], ADJUST_LOWER, 0);
                 assertEquals(Math.max(0, volume - volumeDelta),
@@ -457,6 +451,88 @@
         assertFalse(mAudioManager.isMusicActive());
     }
 
+    public void testMute() {
+        int[] streams = {
+                AudioManager.STREAM_VOICE_CALL,
+                AudioManager.STREAM_MUSIC,
+                AudioManager.STREAM_RING,
+                AudioManager.STREAM_ALARM,
+                AudioManager.STREAM_NOTIFICATION,
+                AudioManager.STREAM_SYSTEM };
+
+        int muteAffectedStreams = System.getInt(mContext.getContentResolver(),
+                System.MUTE_STREAMS_AFFECTED,
+                        // Same defaults as in AudioService. Should be kept in
+                        // sync.
+                        ((1 << AudioManager.STREAM_MUSIC) |
+                                (1 << AudioManager.STREAM_RING) |
+                                (1 << AudioManager.STREAM_NOTIFICATION) |
+                                (1 << AudioManager.STREAM_SYSTEM)));
+        if (mUseFixedVolume) {
+            for (int i = 0; i < streams.length; i++) {
+                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+                assertFalse("Muting should not affect a fixed volume device.",
+                        mAudioManager.isStreamMute(streams[i]));
+
+                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+                assertFalse("Toggling mute should not affect a fixed volume device.",
+                        mAudioManager.isStreamMute(streams[i]));
+
+                mAudioManager.setStreamMute(streams[i], true);
+                assertFalse("Muting should not affect a fixed volume device.",
+                        mAudioManager.isStreamMute(streams[i]));
+            }
+            return;
+        }
+        // This ensures we're out of vibrate or silent modes.
+        mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+        for (int i = 0; i < streams.length; i++) {
+            // ensure each stream is on and turned up.
+            mAudioManager.setStreamVolume(streams[i], mAudioManager.getStreamMaxVolume(streams[i]),
+                    0);
+            if (((1 << streams[i]) & muteAffectedStreams) == 0) {
+                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+                assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+                        mAudioManager.isStreamMute(streams[i]));
+                mAudioManager.setStreamMute(streams[i], true);
+                assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+                        mAudioManager.isStreamMute(streams[i]));
+                mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+                assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+                        mAudioManager.isStreamMute(streams[i]));
+                continue;
+            }
+            mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+            assertTrue("Muting stream " + streams[i] + " failed.",
+                    mAudioManager.isStreamMute(streams[i]));
+
+            mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
+            assertFalse("Unmuting stream " + streams[i] + " failed.",
+                    mAudioManager.isStreamMute(streams[i]));
+
+            mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+            assertTrue("Toggling mute on stream " + streams[i] + " failed.",
+                    mAudioManager.isStreamMute(streams[i]));
+
+            mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+            assertFalse("Toggling mute on stream " + streams[i] + " failed.",
+                    mAudioManager.isStreamMute(streams[i]));
+
+            mAudioManager.setStreamMute(streams[i], true);
+            assertTrue("Muting stream " + streams[i] + " using setStreamMute failed",
+                    mAudioManager.isStreamMute(streams[i]));
+
+            // mute it three more times to verify the ref counting is gone.
+            mAudioManager.setStreamMute(streams[i], true);
+            mAudioManager.setStreamMute(streams[i], true);
+            mAudioManager.setStreamMute(streams[i], true);
+
+            mAudioManager.setStreamMute(streams[i], false);
+            assertFalse("Unmuting stream " + streams[i] + " using setStreamMute failed.",
+                    mAudioManager.isStreamMute(streams[i]));
+        }
+    }
+
     public void testSetInvalidRingerMode() {
         int ringerMode = mAudioManager.getRingerMode();
         mAudioManager.setRingerMode(-1337);
@@ -467,11 +543,6 @@
     }
 
     private int getVolumeDelta(int volume) {
-        if (!mUseMasterVolume) {
-            return 1;
-        }
-        int volumeDelta = mMasterVolumeMap.floorEntry(volume).getValue();
-        assertTrue(volumeDelta > 0);
-        return volumeDelta;
+        return 1;
     }
 }
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index 7ff631f..2652ce8 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -17,26 +17,41 @@
 package android.media.cts;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 
 import android.content.pm.PackageManager;
+import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioFormat;
 import android.media.AudioRecord;
-import android.media.MediaRecorder;
 import android.media.AudioRecord.OnRecordPositionUpdateListener;
+import android.media.cts.AudioHelper;
+import android.media.MediaRecorder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.test.AndroidTestCase;
+import android.util.Log;
+import com.android.cts.util.ReportLog;
+import com.android.cts.util.ResultType;
+import com.android.cts.util.ResultUnit;
 
-public class AudioRecordTest extends AndroidTestCase {
-
+public class AudioRecordTest extends CtsAndroidTestCase {
+    private final static String TAG = "AudioRecordTest";
     private AudioRecord mAudioRecord;
     private int mHz = 44100;
     private boolean mIsOnMarkerReachedCalled;
     private boolean mIsOnPeriodicNotificationCalled;
     private boolean mIsHandleMessageCalled;
     private Looper mLooper;
-    private int MAX_RECORD_START_TIME_MS = 100;
+    // For doTest
+    private int mMarkerPeriodInFrames;
+    private int mMarkerPosition;
+    private Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            mIsHandleMessageCalled = true;
+            super.handleMessage(msg);
+        }
+    };
 
     @Override
     protected void setUp() throws Exception {
@@ -212,7 +227,436 @@
         assertEquals(AudioRecord.STATE_UNINITIALIZED, mAudioRecord.getState());
     }
 
+    public void testAudioRecordResamplerStereo8Bit() throws Exception {
+        doTest("ResamplerStereo8Bit", false /*localRecord*/, false /*customHandler*/,
+                0 /*periodsPerSecond*/, 3 /*markerPeriodsPerSecond*/,
+                true /*useByteBuffer*/,  true /*blocking*/,
+                false /*auditRecording*/, 45000 /*TEST_SR*/,
+                AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_8BIT);
+    }
+
+    public void testAudioRecordLocalMono16Bit() throws Exception {
+        doTest("LocalMono16Bit", true /*localRecord*/, false /*customHandler*/,
+                30 /*periodsPerSecond*/, 2 /*markerPeriodsPerSecond*/,
+                false /*useByteBuffer*/, true /*blocking*/,
+                false /*auditRecording*/, 8000 /*TEST_SR*/,
+                AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
+    }
+
+    public void testAudioRecordMonoFloat() throws Exception {
+        doTest("MonoFloat", false /*localRecord*/, true /*customHandler*/,
+                30 /*periodsPerSecond*/, 2 /*markerPeriodsPerSecond*/,
+                false /*useByteBuffer*/, true /*blocking*/,
+                false /*auditRecording*/, 32000 /*TEST_SR*/,
+                AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_FLOAT);
+    }
+
+    public void testAudioRecordLocalNonblockingStereoFloat() throws Exception {
+        doTest("LocalNonblockingStereoFloat", true /*localRecord*/, true /*customHandler*/,
+                2 /*periodsPerSecond*/, 0 /*markerPeriodsPerSecond*/,
+                false /*useByteBuffer*/, false /*blocking*/,
+                false /*auditRecording*/, 48000 /*TEST_SR*/,
+                AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_FLOAT);
+    }
+
+    public void testAudioRecordByteBufferAuditResamplerStereoFloat() throws Exception {
+        doTest("testAudioRecordByteBufferAuditResamplerStereoFloat",
+                false /*localRecord*/, true /*customHandler*/,
+                2 /*periodsPerSecond*/, 0 /*markerPeriodsPerSecond*/,
+                true /*useByteBuffer*/, true /*blocking*/,
+                true /*auditRecording*/, 17000 /*TEST_SR*/,
+                AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_FLOAT);
+    }
+
+    private void doTest(String reportName, boolean localRecord, boolean customHandler,
+            int periodsPerSecond, int markerPeriodsPerSecond,
+            boolean useByteBuffer, boolean blocking, boolean auditRecording,
+            final int TEST_SR, final int TEST_CONF, final int TEST_FORMAT) throws Exception {
+        if (!hasMicrophone()) {
+            return;
+        }
+        // audit recording plays back recorded audio, so use longer test timing
+        final int TEST_TIME_MS = auditRecording ? 10000 : 2000;
+        final int TEST_SOURCE = MediaRecorder.AudioSource.DEFAULT;
+        mIsHandleMessageCalled = false;
+
+        final int bufferSizeInBytes =
+                AudioRecord.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+        assertTrue(bufferSizeInBytes > 0);
+
+        final AudioRecord record;
+        final AudioHelper
+                .MakeSomethingAsynchronouslyAndLoop<AudioRecord> makeSomething;
+
+        if (auditRecording) {
+            if (localRecord) {
+                makeSomething = null;
+                record = new AudioHelper.AudioRecordAudit(
+                        TEST_SOURCE,
+                        TEST_SR, TEST_CONF,
+                        TEST_FORMAT, bufferSizeInBytes);
+            } else {
+                makeSomething =
+                        new AudioHelper.MakeSomethingAsynchronouslyAndLoop<AudioRecord>(
+                                new AudioHelper.MakesSomething<AudioRecord>() {
+                                    @Override
+                                    public AudioRecord makeSomething() {
+                                        return new AudioHelper.AudioRecordAudit(
+                                                TEST_SOURCE,
+                                                TEST_SR, TEST_CONF,
+                                                TEST_FORMAT, bufferSizeInBytes);
+                                    }
+                                }
+                                );
+                // create AudioRecord on different thread's looper.
+                record = makeSomething.make();
+            }
+        } else {
+            if (localRecord) {
+                makeSomething = null;
+                record = new AudioRecord(TEST_SOURCE, TEST_SR, TEST_CONF,
+                        TEST_FORMAT, bufferSizeInBytes);
+            } else {
+                makeSomething =
+                        new AudioHelper.MakeSomethingAsynchronouslyAndLoop<AudioRecord>(
+                                new AudioHelper.MakesSomething<AudioRecord>() {
+                                    @Override
+                                    public AudioRecord makeSomething() {
+                                        return new AudioRecord(TEST_SOURCE, TEST_SR, TEST_CONF,
+                                                TEST_FORMAT, bufferSizeInBytes);
+                                    }
+                                }
+                                );
+               // create AudioRecord on different thread's looper.
+               record = makeSomething.make();
+            }
+        }
+        // AudioRecord creation may have silently failed, check state now
+        assertEquals(AudioRecord.STATE_INITIALIZED, record.getState());
+
+        final MockOnRecordPositionUpdateListener listener;
+        if (customHandler) {
+            listener = new MockOnRecordPositionUpdateListener(record, mHandler);
+        } else {
+            listener = new MockOnRecordPositionUpdateListener(record);
+        }
+
+        if (markerPeriodsPerSecond != 0) {
+            mMarkerPeriodInFrames = TEST_SR / markerPeriodsPerSecond;
+            mMarkerPosition = mMarkerPeriodInFrames;
+            assertEquals(AudioRecord.SUCCESS,
+                    record.setNotificationMarkerPosition(mMarkerPosition));
+        } else {
+            mMarkerPeriodInFrames = 0;
+        }
+        final int updatePeriodInFrames = (periodsPerSecond == 0)
+                ? 0 : TEST_SR / periodsPerSecond;
+        assertEquals(AudioRecord.SUCCESS,
+                record.setPositionNotificationPeriod(updatePeriodInFrames));
+
+        listener.start(TEST_SR);
+        record.startRecording();
+        assertEquals(AudioRecord.RECORDSTATE_RECORDING, record.getRecordingState());
+        long startTime = System.currentTimeMillis();
+
+        // For our tests, we could set test duration by timed sleep or by # frames received.
+        // Since we don't know *exactly* when AudioRecord actually begins recording,
+        // we end the test by # frames read.
+        final int numChannels =  AudioFormat.channelCountFromInChannelMask(TEST_CONF);
+        final int bytesPerSample = AudioFormat.getBytesPerSample(TEST_FORMAT);
+        final int bytesPerFrame = numChannels * bytesPerSample;
+        final int targetSamples = TEST_TIME_MS * TEST_SR * numChannels / 1000;
+        final int BUFFER_FRAMES = 512;
+        final int BUFFER_SAMPLES = BUFFER_FRAMES * numChannels;
+        // TODO: verify behavior when buffer size is not a multiple of frame size.
+
+        // After starting, there is no guarantee when the first frame of data is read.
+        long firstSampleTime = 0;
+        int samplesRead = 0;
+        if (useByteBuffer) {
+            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER_SAMPLES * bytesPerSample);
+            while (samplesRead < targetSamples) {
+                // the first time through, we read a single frame.
+                // this sets the recording anchor position.
+                int amount = samplesRead == 0 ? numChannels :
+                    Math.min(BUFFER_SAMPLES, targetSamples - samplesRead);
+                amount *= bytesPerSample;    // in bytes
+                // read always places data at the start of the byte buffer with
+                // position and limit are ignored.  test this by setting
+                // position and limit to arbitrary values here.
+                final int lastPosition = 7;
+                final int lastLimit = 13;
+                byteBuffer.position(lastPosition);
+                byteBuffer.limit(lastLimit);
+                int ret = record.read(byteBuffer, amount);
+                // so long as amount requested in bytes is a multiple of the frame size
+                // we expect the byte buffer request to be filled.  Caution: the
+                // byte buffer data will be in native endian order, not Java order.
+                assertEquals(amount, ret); // blocking
+                // position, limit are not changed by read().
+                assertEquals(lastPosition, byteBuffer.position());
+                assertEquals(lastLimit, byteBuffer.limit());
+                if (samplesRead == 0) {
+                    firstSampleTime = System.currentTimeMillis();
+                }
+                samplesRead += ret / bytesPerSample;
+            }
+        } else {
+            switch (TEST_FORMAT) {
+            case AudioFormat.ENCODING_PCM_8BIT: {
+                // For 8 bit data, use bytes
+                assertTrue(blocking); // always blocking (for now)
+                byte[] byteData = new byte[BUFFER_SAMPLES];
+                while (samplesRead < targetSamples) {
+                    // the first time through, we read a single frame.
+                    // this sets the recording anchor position.
+                    int amount = samplesRead == 0 ? numChannels :
+                        Math.min(BUFFER_SAMPLES, targetSamples - samplesRead);
+                    int ret = record.read(byteData, 0, amount);
+                    assertEquals(amount, ret); // blocking
+                    if (samplesRead == 0) {
+                        firstSampleTime = System.currentTimeMillis();
+                    }
+                    samplesRead += ret;
+                }
+            } break;
+            case AudioFormat.ENCODING_PCM_16BIT: {
+                // For 16 bit data, use shorts
+                assertTrue(blocking); // always blocking (for now)
+                short[] shortData = new short[BUFFER_SAMPLES];
+                while (samplesRead < targetSamples) {
+                    // the first time through, we read a single frame.
+                    // this sets the recording anchor position.
+                    int amount = samplesRead == 0 ? numChannels :
+                        Math.min(BUFFER_SAMPLES, targetSamples - samplesRead);
+                    int ret = record.read(shortData, 0, amount);
+                    assertEquals(amount, ret); // blocking
+                    if (samplesRead == 0) {
+                        firstSampleTime = System.currentTimeMillis();
+                    }
+                    samplesRead += ret;
+                }
+            } break;
+            case AudioFormat.ENCODING_PCM_FLOAT: {
+                float[] floatData = new float[BUFFER_SAMPLES];
+                while (samplesRead < targetSamples) {
+                    // the first time through, we read a single frame.
+                    // this sets the recording anchor position.
+                    int amount = samplesRead == 0 ? numChannels :
+                        Math.min(BUFFER_SAMPLES, targetSamples - samplesRead);
+                    int ret = record.read(floatData, 0, amount, blocking ?
+                            AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
+                    if (blocking) {
+                        assertEquals(amount, ret); // blocking
+                    } else {
+                        assertTrue(ret >= 0 && ret <= amount);
+                    }
+                    if (samplesRead == 0) {
+                        firstSampleTime = System.currentTimeMillis();
+                    }
+                    samplesRead += ret;
+                }
+            } break;
+            }
+        }
+
+        // We've read all the frames, now check the record timing.
+        final long endTime = System.currentTimeMillis();
+        //Log.d(TAG, "first sample time " + (firstSampleTime - startTime)
+        //        + " test time " + (endTime - firstSampleTime));
+        // Verify recording starts within 200 ms of record.startRecording() (typical 100ms)
+        // Verify recording completes within 50 ms of expected test time (typical 20ms)
+        assertEquals(0, firstSampleTime - startTime, 200);
+        assertEquals(TEST_TIME_MS, endTime - firstSampleTime, auditRecording ? 1000 : 50);
+
+        // Even though we've read all the frames we want, the events may not be sent to
+        // the listeners (events are handled through a separate internal callback thread).
+        // One must sleep to make sure the last event(s) come in.
+        Thread.sleep(30);
+
+        record.stop();
+        assertEquals(AudioRecord.RECORDSTATE_STOPPED, record.getRecordingState());
+
+        final long stopTime = System.currentTimeMillis();
+
+        // stop listening - we should be done.
+        // Caution M behavior and likely much earlier:
+        // we assume no events can happen after stop(), but this may not
+        // always be true as stop can take 100ms to complete (as it may disable
+        // input recording on the hal); thus the event handler may be block with
+        // valid events, issuing right after stop completes. Except for those events,
+        // no other events should show up after stop.
+        // This behavior may change in the future but we account for it here in testing.
+        listener.stop();
+
+        // clean up
+        if (makeSomething != null) {
+            makeSomething.join();
+        }
+        listener.release();
+        record.release();
+        if (auditRecording) { // don't check timing if auditing (messes up timing)
+            return;
+        }
+        final int markerPeriods = markerPeriodsPerSecond * TEST_TIME_MS / 1000;
+        final int updatePeriods = periodsPerSecond * TEST_TIME_MS / 1000;
+        final int markerPeriodsMax =
+                markerPeriodsPerSecond * (int)(stopTime - firstSampleTime) / 1000 + 1;
+        final int updatePeriodsMax =
+                periodsPerSecond * (int)(stopTime - firstSampleTime) / 1000 + 1;
+
+        // collect statistics
+        final ArrayList<Integer> markerList = listener.getMarkerList();
+        final ArrayList<Integer> periodicList = listener.getPeriodicList();
+        // verify count of markers and periodic notifications.
+        // there could be an extra notification since we don't stop() immediately
+        // rather wait for potential events to come in.
+        //Log.d(TAG, "markerPeriods " + markerPeriods +
+        //        " markerPeriodsReceived " + markerList.size());
+        //Log.d(TAG, "updatePeriods " + updatePeriods +
+        //        " updatePeriodsReceived " + periodicList.size());
+        assertTrue(markerPeriods <= markerList.size()
+                && markerList.size() <= markerPeriodsMax);
+        assertTrue(updatePeriods <= periodicList.size()
+                && periodicList.size() <= updatePeriodsMax);
+
+        // Since we don't have accurate positioning of the start time of the recorder,
+        // and there is no record.getPosition(), we consider only differential timing
+        // from the first marker or periodic event.
+        final int toleranceInFrames = TEST_SR * 80 / 1000; // 80 ms
+
+        AudioHelper.Statistics markerStat = new AudioHelper.Statistics();
+        for (int i = 1; i < markerList.size(); ++i) {
+            final int expected = mMarkerPeriodInFrames * i;
+            final int actual = markerList.get(i) - markerList.get(0);
+            //Log.d(TAG, "Marker: " + i + " expected(" + expected + ")  actual(" + actual
+            //        + ")  diff(" + (actual - expected) + ")"
+            //        + " tolerance " + toleranceInFrames);
+            assertEquals(expected, actual, toleranceInFrames);
+            markerStat.add((double)(actual - expected) * 1000 / TEST_SR);
+        }
+
+        AudioHelper.Statistics periodicStat = new AudioHelper.Statistics();
+        for (int i = 1; i < periodicList.size(); ++i) {
+            final int expected = updatePeriodInFrames * i;
+            final int actual = periodicList.get(i) - periodicList.get(0);
+            //Log.d(TAG, "Update: " + i + " expected(" + expected + ")  actual(" + actual
+            //        + ")  diff(" + (actual - expected) + ")"
+            //        + " tolerance " + toleranceInFrames);
+            assertEquals(expected, actual, toleranceInFrames);
+            periodicStat.add((double)(actual - expected) * 1000 / TEST_SR);
+        }
+
+        // report this
+        ReportLog log = getReportLog();
+        log.printValue(reportName + ": startRecording lag", firstSampleTime - startTime,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Total record time expected", TEST_TIME_MS,
+                ResultType.NEUTRAL, ResultUnit.MS);
+        log.printValue(reportName + ": Total record time actual", (endTime - firstSampleTime),
+                ResultType.NEUTRAL, ResultUnit.MS);
+        log.printValue(reportName + ": Total markers expected", markerPeriods,
+                ResultType.NEUTRAL, ResultUnit.COUNT);
+        log.printValue(reportName + ": Total markers actual", markerList.size(),
+                ResultType.NEUTRAL, ResultUnit.COUNT);
+        log.printValue(reportName + ": Total periods expected", updatePeriods,
+                ResultType.NEUTRAL, ResultUnit.COUNT);
+        log.printValue(reportName + ": Total periods actual", periodicList.size(),
+                ResultType.NEUTRAL, ResultUnit.COUNT);
+        log.printValue(reportName + ": Average Marker diff", markerStat.getAvg(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Maximum Marker abs diff", markerStat.getMaxAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Average Marker abs diff", markerStat.getAvgAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Average Periodic diff", periodicStat.getAvg(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Maximum Periodic abs diff", periodicStat.getMaxAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Average Periodic abs diff", periodicStat.getAvgAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printSummary(reportName + ": Unified abs diff",
+                (periodicStat.getAvgAbs() + markerStat.getAvgAbs()) / 2,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+    }
+
+    private class MockOnRecordPositionUpdateListener
+                                        implements OnRecordPositionUpdateListener {
+        public MockOnRecordPositionUpdateListener(AudioRecord record) {
+            mAudioRecord = record;
+            record.setRecordPositionUpdateListener(this);
+        }
+
+        public MockOnRecordPositionUpdateListener(AudioRecord record, Handler handler) {
+            mAudioRecord = record;
+            record.setRecordPositionUpdateListener(this, handler);
+        }
+
+        public synchronized void onMarkerReached(AudioRecord record) {
+            if (mIsTestActive) {
+                int position = getPosition();
+                mOnMarkerReachedCalled.add(position);
+                mMarkerPosition += mMarkerPeriodInFrames;
+                assertEquals(AudioRecord.SUCCESS,
+                        mAudioRecord.setNotificationMarkerPosition(mMarkerPosition));
+            } else {
+                // stop() is not sufficient to end all notifications
+                // as is not synchronous with the event handling thread
+                // so we comment out the line below.
+                // fail("onMarkerReached called when not active");
+            }
+        }
+
+        public synchronized void onPeriodicNotification(AudioRecord record) {
+            if (mIsTestActive) {
+                int position = getPosition();
+                mOnPeriodicNotificationCalled.add(position);
+            } else {
+                // see above comments about stop
+                // fail("onPeriodicNotification called when not active");
+            }
+        }
+
+        public synchronized void start(int sampleRate) {
+            mIsTestActive = true;
+            mSampleRate = sampleRate;
+            mStartTime = System.currentTimeMillis();
+        }
+
+        public synchronized void stop() {
+            mIsTestActive = false;
+        }
+
+        public ArrayList<Integer> getMarkerList() {
+            return mOnMarkerReachedCalled;
+        }
+
+        public ArrayList<Integer> getPeriodicList() {
+            return mOnPeriodicNotificationCalled;
+        }
+
+        public synchronized void release() {
+            mAudioRecord.setRecordPositionUpdateListener(null);
+            mAudioRecord = null;
+        }
+
+        private int getPosition() {
+            // we don't have mAudioRecord.getRecordPosition();
+            // so we fake this by timing.
+            long delta = System.currentTimeMillis() - mStartTime;
+            return (int)(delta * mSampleRate / 1000);
+        }
+
+        private long mStartTime;
+        private int mSampleRate;
+        private boolean mIsTestActive = true;
+        private AudioRecord mAudioRecord;
+        private ArrayList<Integer> mOnMarkerReachedCalled = new ArrayList<Integer>();
+        private ArrayList<Integer> mOnPeriodicNotificationCalled = new ArrayList<Integer>();
+    }
+
     private boolean hasMicrophone() {
-        return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
+        return getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_MICROPHONE);
     }
 }
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 4f6d27f..8ac709a 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -1360,6 +1360,11 @@
     }
 
     public void testPlayStaticData() throws Exception {
+        if (!hasAudioOutput()) {
+            Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
+                    + "audio output HAL");
+            return;
+        }
         // constants for test
         final String TEST_NAME = "testPlayStaticData";
         final int TEST_FORMAT_ARRAY[] = {  // 6 chirps repeated (TEST_LOOPS+1) times, 3 times
@@ -1396,18 +1401,18 @@
                     final long MILLISECONDS_PER_SECOND = 1000;
                     AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR,
                             TEST_CONF, TEST_FORMAT, bufferSize, TEST_MODE);
-                    assertEquals(TEST_NAME, track.getState(), AudioTrack.STATE_NO_STATIC_DATA);
+                    assertEquals(TEST_NAME, AudioTrack.STATE_NO_STATIC_DATA, track.getState());
 
                     // -------- test --------------
 
                     // test setLoopPoints and setPosition can be called here.
                     assertEquals(TEST_NAME,
-                            track.setPlaybackHeadPosition(bufferFrames/2),
-                            android.media.AudioTrack.SUCCESS);
+                            android.media.AudioTrack.SUCCESS,
+                            track.setPlaybackHeadPosition(bufferFrames/2));
                     assertEquals(TEST_NAME,
+                            android.media.AudioTrack.SUCCESS,
                             track.setLoopPoints(
-                                    0 /*startInFrames*/, bufferFrames, 10 /*loopCount*/),
-                            android.media.AudioTrack.SUCCESS);
+                                    0 /*startInFrames*/, bufferFrames, 10 /*loopCount*/));
                     // only need to write once to the static track
                     switch (TEST_FORMAT) {
                     case AudioFormat.ENCODING_PCM_8BIT: {
@@ -1415,35 +1420,35 @@
                                 bufferSamples, TEST_SR,
                                 testFrequency, TEST_SWEEP);
                         assertEquals(TEST_NAME,
-                                track.write(data, 0 /*offsetInBytes*/, data.length),
-                                bufferSamples);
+                                bufferSamples,
+                                track.write(data, 0 /*offsetInBytes*/, data.length));
                         } break;
                     case AudioFormat.ENCODING_PCM_16BIT: {
                         short data[] = createSoundDataInShortArray(
                                 bufferSamples, TEST_SR,
                                 testFrequency, TEST_SWEEP);
                         assertEquals(TEST_NAME,
-                                track.write(data, 0 /*offsetInBytes*/, data.length),
-                                bufferSamples);
+                                bufferSamples,
+                                track.write(data, 0 /*offsetInBytes*/, data.length));
                         } break;
                     case AudioFormat.ENCODING_PCM_FLOAT: {
                         float data[] = createSoundDataInFloatArray(
                                 bufferSamples, TEST_SR,
                                 testFrequency, TEST_SWEEP);
                         assertEquals(TEST_NAME,
+                                bufferSamples,
                                 track.write(data, 0 /*offsetInBytes*/, data.length,
-                                        AudioTrack.WRITE_BLOCKING),
-                                bufferSamples);
+                                        AudioTrack.WRITE_BLOCKING));
                         } break;
                     }
-                    assertEquals(TEST_NAME, track.getState(), AudioTrack.STATE_INITIALIZED);
+                    assertEquals(TEST_NAME, AudioTrack.STATE_INITIALIZED, track.getState());
                     // test setLoopPoints and setPosition can be called here.
                     assertEquals(TEST_NAME,
-                            track.setPlaybackHeadPosition(0 /*positionInFrames*/),
-                            android.media.AudioTrack.SUCCESS);
+                            android.media.AudioTrack.SUCCESS,
+                            track.setPlaybackHeadPosition(0 /*positionInFrames*/));
                     assertEquals(TEST_NAME,
-                            track.setLoopPoints(0 /*startInFrames*/, bufferFrames, TEST_LOOPS),
-                            android.media.AudioTrack.SUCCESS);
+                            android.media.AudioTrack.SUCCESS,
+                            track.setLoopPoints(0 /*startInFrames*/, bufferFrames, TEST_LOOPS));
 
                     track.play();
                     Thread.sleep(seconds * MILLISECONDS_PER_SECOND * (TEST_LOOPS + 1));
@@ -1452,7 +1457,7 @@
                     // Check position after looping. AudioTrack.getPlaybackHeadPosition() returns
                     // the running count of frames played, not the actual static buffer position.
                     int position = track.getPlaybackHeadPosition();
-                    assertEquals(TEST_NAME, position, bufferFrames * (TEST_LOOPS + 1));
+                    assertEquals(TEST_NAME, bufferFrames * (TEST_LOOPS + 1), position);
 
                     track.stop();
                     Thread.sleep(WAIT_MSEC);
@@ -1673,9 +1678,10 @@
 
     public void testGetTimestamp() throws Exception {
         if (!hasAudioOutput()) {
+            Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
+                    + "audio output HAL");
             return;
         }
-        
         // constants for test
         final String TEST_NAME = "testGetTimestamp";
         final int TEST_SR = 22050;
@@ -1802,6 +1808,70 @@
         }
     }
 
+    public void testVariableRatePlayback() throws Exception {
+        final String TEST_NAME = "testVariableRatePlayback";
+        final int TEST_SR = 24000;
+        final int TEST_FINAL_SR = 96000;
+        final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
+        final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT; // required for test
+        final int TEST_MODE = AudioTrack.MODE_STATIC; // required for test
+        final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+        final int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+        final int bufferSizeInBytes = minBuffSize * 100;
+        final int numChannels =  AudioFormat.channelCountFromOutChannelMask(TEST_CONF);
+        final int bytesPerSample = AudioFormat.getBytesPerSample(TEST_FORMAT);
+        final int bytesPerFrame = numChannels * bytesPerSample;
+        final int frameCount = bufferSizeInBytes / bytesPerFrame;
+
+        AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF,
+                TEST_FORMAT, bufferSizeInBytes, TEST_MODE);
+
+        // create byte array and write it
+        byte[] vai = createSoundDataInByteArray(bufferSizeInBytes, TEST_SR, 600);
+        assertEquals(vai.length, track.write(vai, 0 /* offsetInBytes */, vai.length));
+
+        // sweep up test and sweep down test
+        int[] sampleRates = {TEST_SR, TEST_FINAL_SR};
+        int[] deltaMss = {10, 10};
+        int[] deltaFreqs = {200, -200};
+
+        for (int i = 0; i < 2; ++i) {
+            int remainingTime;
+            int sampleRate = sampleRates[i];
+            final int deltaMs = deltaMss[i];
+            final int deltaFreq = deltaFreqs[i];
+            final int lastCheckMs = 500; // check the last 500 ms
+
+            assertEquals(TEST_NAME, AudioTrack.SUCCESS, track.setPlaybackRate(sampleRate));
+            track.play();
+            do {
+                Thread.sleep(deltaMs);
+                final int position = track.getPlaybackHeadPosition();
+                sampleRate += deltaFreq;
+                sampleRate = Math.min(TEST_FINAL_SR, Math.max(TEST_SR, sampleRate));
+                assertEquals(TEST_NAME, AudioTrack.SUCCESS, track.setPlaybackRate(sampleRate));
+                remainingTime = (int)((double)(frameCount - position) * 1000
+                        / sampleRate / bytesPerFrame);
+            } while (remainingTime >= lastCheckMs + deltaMs);
+
+            // ensure the final frequency set is constant and plays frames as expected
+            final int position1 = track.getPlaybackHeadPosition();
+            Thread.sleep(lastCheckMs);
+            final int position2 = track.getPlaybackHeadPosition();
+
+            final int tolerance60MsInFrames = sampleRate * 60 / 1000;
+            final int expected = lastCheckMs * sampleRate / 1000;
+            final int actual = position2 - position1;
+
+            // Log.d(TAG, "Variable Playback: expected(" + expected + ")  actual(" + actual
+            //        + ")  diff(" + (expected - actual) + ")");
+            assertEquals(expected, actual, tolerance60MsInFrames);
+            track.stop();
+        }
+        track.release();
+    }
+
 /* Do not run in JB-MR1. will be re-opened in the next platform release.
     public void testResourceLeakage() throws Exception {
         final int BUFFER_SIZE = 600 * 1024;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
index eb675fc..353dbcb 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
@@ -16,25 +16,35 @@
 
 package android.media.cts;
 
+import java.util.ArrayList;
 
+import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioTrack;
 import android.media.AudioTrack.OnPlaybackPositionUpdateListener;
+import android.media.cts.AudioHelper;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.test.AndroidTestCase;
+import android.util.Log;
+import com.android.cts.util.ReportLog;
+import com.android.cts.util.ResultType;
+import com.android.cts.util.ResultUnit;
 
-public class AudioTrack_ListenerTest extends AndroidTestCase {
-    private boolean mOnMarkerReachedCalled;
-    private boolean mOnPeriodicNotificationCalled;
+public class AudioTrack_ListenerTest extends CtsAndroidTestCase {
+    private final static String TAG = "AudioTrack_ListenerTest";
+    private final static int TEST_SR = 11025;
+    private final static int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
+    private final static int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
+    private final static int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+    private final static int TEST_LOOP_FACTOR = 2; // # loops (>= 1) for static tracks
+                                                   // simulated for streaming.
+    private final static int TEST_BUFFER_FACTOR = 25;
     private boolean mIsHandleMessageCalled;
-    private final int TEST_SR = 11025;
-    private final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
-    private final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
-    private final int TEST_MODE = AudioTrack.MODE_STREAM;
-    private final int TEST_STREAM_TYPE1 = AudioManager.STREAM_MUSIC;
+    private int mMarkerPeriodInFrames;
+    private int mMarkerPosition;
+    private int mFrameCount;
     private Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
@@ -42,180 +52,222 @@
             super.handleMessage(msg);
         }
     };
-    private final int mMinBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
-    private AudioTrack mAudioTrack;
-    private OnPlaybackPositionUpdateListener mListener =
-                                new MockOnPlaybackPositionUpdateListener();
-    private MakeSomethingAsynchronouslyAndLoop<AudioTrack> mMakeSomething;
-
-    @Override
-    protected void setUp() throws Exception
-    {
-        super.setUp();
-        if (mAudioTrack == null) {
-            mMakeSomething = new MakeSomethingAsynchronouslyAndLoop<AudioTrack>(
-                new MakesSomething<AudioTrack>() {
-                    @Override
-                    public AudioTrack makeSomething()
-                    {
-                        return new AudioTrack(TEST_STREAM_TYPE1, TEST_SR, TEST_CONF,
-                            TEST_FORMAT, 2 * mMinBuffSize, TEST_MODE);
-                    }
-                }
-            );
-            mAudioTrack = mMakeSomething.make();
-        }
-    }
 
     public void testAudioTrackCallback() throws Exception {
-        mAudioTrack.setPlaybackPositionUpdateListener(mListener);
-        doTest(false /*customHandler*/);
+        doTest("Streaming Local Looper", true /*localTrack*/, false /*customHandler*/,
+                30 /*periodsPerSecond*/, 2 /*markerPeriodsPerSecond*/, AudioTrack.MODE_STREAM);
     }
 
     public void testAudioTrackCallbackWithHandler() throws Exception {
-        mAudioTrack.setPlaybackPositionUpdateListener(mListener, mHandler);
-        doTest(true /*customHandler*/);
-        // ToBeFixed: Handler#handleMessage() is never called
-        // FIXME possibly because the new Handler() is missing the Looper parameter
+        // with 100 periods per second, trigger back-to-back notifications.
+        doTest("Streaming Private Handler", false /*localTrack*/, true /*customHandler*/,
+                100 /*periodsPerSecond*/, 10 /*markerPeriodsPerSecond*/, AudioTrack.MODE_STREAM);
+        // verify mHandler is used only for accessing its associated Looper
         assertFalse(mIsHandleMessageCalled);
     }
 
-    private void doTest(boolean customHandler) throws Exception {
-        mOnMarkerReachedCalled = false;
-        mOnPeriodicNotificationCalled = false;
-        byte[] vai = AudioTrackTest.createSoundDataInByteArray(2 * mMinBuffSize, TEST_SR, 1024);
-        int markerInFrames = vai.length / 4;
-        assertEquals(AudioTrack.SUCCESS, mAudioTrack.setNotificationMarkerPosition(markerInFrames));
-        int periodInFrames = vai.length / 2;
-        assertEquals(AudioTrack.SUCCESS, mAudioTrack.setPositionNotificationPeriod(periodInFrames));
-
-        boolean hasPlayed = false;
-        int written = 0;
-        while (written < vai.length) {
-            written += mAudioTrack.write(vai, written, vai.length - written);
-            if (!hasPlayed) {
-                mAudioTrack.play();
-                hasPlayed = true;
-            }
-        }
-
-        final int numChannels = (TEST_CONF == AudioFormat.CHANNEL_CONFIGURATION_STEREO) ? 2 : 1;
-        final int bytesPerSample = (TEST_FORMAT == AudioFormat.ENCODING_PCM_16BIT) ? 2 : 1;
-        final int bytesPerFrame = numChannels * bytesPerSample;
-        final int sampleLengthMs = (int)(1000 * ((float)vai.length / TEST_SR / bytesPerFrame));
-        Thread.sleep(sampleLengthMs + 1000);
-        if (!customHandler) {
-            assertTrue(mOnMarkerReachedCalled);
-            assertTrue(mOnPeriodicNotificationCalled);
-        }
-        mAudioTrack.stop();
+    public void testStaticAudioTrackCallback() throws Exception {
+        doTest("Static", false /*localTrack*/, false /*customHandler*/,
+                100 /*periodsPerSecond*/, 10 /*markerPeriodsPerSecond*/, AudioTrack.MODE_STATIC);
     }
 
-    // lightweight java.util.concurrent.Future*
-    private static class FutureLatch<T>
-    {
-        private T mValue;
-        private boolean mSet;
-        public void set(T value)
-        {
-            synchronized (this) {
-                assert !mSet;
-                mValue = value;
-                mSet = true;
-                notify();
-            }
+    public void testStaticAudioTrackCallbackWithHandler() throws Exception {
+        doTest("Static Private Handler", false /*localTrack*/, true /*customHandler*/,
+                30 /*periodsPerSecond*/, 2 /*markerPeriodsPerSecond*/, AudioTrack.MODE_STATIC);
+        // verify mHandler is used only for accessing its associated Looper
+        assertFalse(mIsHandleMessageCalled);
+    }
+
+    private void doTest(String reportName, boolean localTrack, boolean customHandler,
+            int periodsPerSecond, int markerPeriodsPerSecond, final int mode) throws Exception {
+        mIsHandleMessageCalled = false;
+        final int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+        final int bufferSizeInBytes;
+        if (mode == AudioTrack.MODE_STATIC && TEST_LOOP_FACTOR > 1) {
+            // use setLoopPoints for static mode
+            bufferSizeInBytes = minBuffSize * TEST_BUFFER_FACTOR;
+            mFrameCount = bufferSizeInBytes * TEST_LOOP_FACTOR;
+        } else {
+            bufferSizeInBytes = minBuffSize * TEST_BUFFER_FACTOR * TEST_LOOP_FACTOR;
+            mFrameCount = bufferSizeInBytes;
         }
-        public T get()
-        {
-            T value;
-            synchronized (this) {
-                while (!mSet) {
-                    try {
-                        wait();
-                    } catch (InterruptedException e) {
-                        ;
+
+        final AudioTrack track;
+        final AudioHelper.MakeSomethingAsynchronouslyAndLoop<AudioTrack> makeSomething;
+        if (localTrack) {
+            makeSomething = null;
+            track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF,
+                    TEST_FORMAT, bufferSizeInBytes, mode);
+        } else {
+            makeSomething =
+                    new AudioHelper.MakeSomethingAsynchronouslyAndLoop<AudioTrack>(
+                    new AudioHelper.MakesSomething<AudioTrack>() {
+                        @Override
+                        public AudioTrack makeSomething() {
+                            return new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF,
+                                TEST_FORMAT, bufferSizeInBytes, mode);
+                        }
                     }
-                }
-                value = mValue;
-            }
-            return value;
+                );
+           // create audiotrack on different thread's looper.
+           track = makeSomething.make();
         }
-    }
-
-    // represents a factory for T
-    private interface MakesSomething<T>
-    {
-        T makeSomething();
-    }
-
-    // used to construct an object in the context of an asynchronous thread with looper
-    private static class MakeSomethingAsynchronouslyAndLoop<T>
-    {
-        private Thread mThread;
-        volatile private Looper mLooper;
-        private final MakesSomething<T> mWhatToMake;
-
-        public MakeSomethingAsynchronouslyAndLoop(MakesSomething<T> whatToMake)
-        {
-            assert whatToMake != null;
-            mWhatToMake = whatToMake;
+        final MockOnPlaybackPositionUpdateListener listener;
+        if (customHandler) {
+            listener = new MockOnPlaybackPositionUpdateListener(track, mHandler);
+        } else {
+            listener = new MockOnPlaybackPositionUpdateListener(track);
         }
 
-        public T make()
-        {
-            final FutureLatch<T> futureLatch = new FutureLatch<T>();
-            mThread = new Thread()
-            {
-                @Override
-                public void run()
-                {
-                    Looper.prepare();
-                    mLooper = Looper.myLooper();
-                    T something = mWhatToMake.makeSomething();
-                    futureLatch.set(something);
-                    Looper.loop();
-                }
-            };
-            mThread.start();
-            return futureLatch.get();
+        byte[] vai = AudioTrackTest.createSoundDataInByteArray(bufferSizeInBytes, TEST_SR, 1024);
+        int markerPeriods = Math.max(3, mFrameCount * markerPeriodsPerSecond / TEST_SR);
+        mMarkerPeriodInFrames = mFrameCount / markerPeriods;
+        markerPeriods = mFrameCount / mMarkerPeriodInFrames; // recalculate due to round-down
+        mMarkerPosition = mMarkerPeriodInFrames;
+        assertEquals(AudioTrack.SUCCESS,
+                track.setNotificationMarkerPosition(mMarkerPosition));
+        int updatePeriods = Math.max(3, mFrameCount * periodsPerSecond / TEST_SR);
+        final int updatePeriodInFrames = mFrameCount / updatePeriods;
+        updatePeriods = mFrameCount / updatePeriodInFrames; // recalculate due to round-down
+        assertEquals(AudioTrack.SUCCESS,
+                track.setPositionNotificationPeriod(updatePeriodInFrames));
+        // set NotificationPeriod before running to ensure better period positional accuracy.
+
+        if (mode == AudioTrack.MODE_STATIC && TEST_LOOP_FACTOR > 1) {
+            track.setLoopPoints(0, vai.length, TEST_LOOP_FACTOR - 1);
         }
-        public void join()
-        {
-            mLooper.quit();
-            try {
-                mThread.join();
-            } catch (InterruptedException e) {
-                ;
-            }
-            // avoid dangling references
-            mLooper = null;
-            mThread = null;
+        // write data with single blocking write, then play.
+        assertEquals(vai.length, track.write(vai, 0 /* offsetInBytes */, vai.length));
+        track.play();
+
+        // sleep until track completes playback - it must complete within 1 second
+        // of the expected length otherwise the periodic test should fail.
+        final int numChannels =  AudioFormat.channelCountFromOutChannelMask(TEST_CONF);
+        final int bytesPerSample = AudioFormat.getBytesPerSample(TEST_FORMAT);
+        final int bytesPerFrame = numChannels * bytesPerSample;
+        final int trackLengthMs = (int)((double)mFrameCount * 1000 / TEST_SR / bytesPerFrame);
+        Thread.sleep(trackLengthMs + 1000);
+
+        // stop listening - we should be done.
+        listener.stop();
+
+        // Beware: stop() resets the playback head position for both static and streaming
+        // audio tracks, so stop() cannot be called while we're still logging playback
+        // head positions. We could recycle the track after stop(), which isn't done here.
+        track.stop();
+
+        // clean up
+        if (makeSomething != null) {
+            makeSomething.join();
         }
+        listener.release();
+        track.release();
+
+        // collect statistics
+        final ArrayList<Integer> markerList = listener.getMarkerList();
+        final ArrayList<Integer> periodicList = listener.getPeriodicList();
+        // verify count of markers and periodic notifications.
+        assertEquals(markerPeriods, markerList.size());
+        assertEquals(updatePeriods, periodicList.size());
+        // verify actual playback head positions returned.
+        // the max diff should really be around 24 ms,
+        // but system load and stability will affect this test;
+        // we use 80ms limit here for failure.
+        final int tolerance80MsInFrames = TEST_SR * 80 / 1000;
+
+        AudioHelper.Statistics markerStat = new AudioHelper.Statistics();
+        for (int i = 0; i < markerPeriods; ++i) {
+            final int expected = mMarkerPeriodInFrames * (i + 1);
+            final int actual = markerList.get(i);
+            // Log.d(TAG, "Marker: expected(" + expected + ")  actual(" + actual
+            //        + ")  diff(" + (actual - expected) + ")");
+            assertEquals(expected, actual, tolerance80MsInFrames);
+            markerStat.add((double)(actual - expected) * 1000 / TEST_SR);
+        }
+
+        AudioHelper.Statistics periodicStat = new AudioHelper.Statistics();
+        for (int i = 0; i < updatePeriods; ++i) {
+            final int expected = updatePeriodInFrames * (i + 1);
+            final int actual = periodicList.get(i);
+            // Log.d(TAG, "Update: expected(" + expected + ")  actual(" + actual
+            //        + ")  diff(" + (actual - expected) + ")");
+            assertEquals(expected, actual, tolerance80MsInFrames);
+            periodicStat.add((double)(actual - expected) * 1000 / TEST_SR);
+        }
+
+        // report this
+        ReportLog log = getReportLog();
+        log.printValue(reportName + ": Average Marker diff", markerStat.getAvg(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Maximum Marker abs diff", markerStat.getMaxAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Average Marker abs diff", markerStat.getAvgAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Average Periodic diff", periodicStat.getAvg(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Maximum Periodic abs diff", periodicStat.getMaxAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printValue(reportName + ": Average Periodic abs diff", periodicStat.getAvgAbs(),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.printSummary(reportName + ": Unified abs diff",
+                (periodicStat.getAvgAbs() + markerStat.getAvgAbs()) / 2,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
     }
 
     private class MockOnPlaybackPositionUpdateListener
                                         implements OnPlaybackPositionUpdateListener {
-
-        public void onMarkerReached(AudioTrack track) {
-            mOnMarkerReachedCalled = true;
+        public MockOnPlaybackPositionUpdateListener(AudioTrack track) {
+            mAudioTrack = track;
+            track.setPlaybackPositionUpdateListener(this);
         }
 
-        public void onPeriodicNotification(AudioTrack track) {
-            mOnPeriodicNotificationCalled = true;
+        public MockOnPlaybackPositionUpdateListener(AudioTrack track, Handler handler) {
+            mAudioTrack = track;
+            track.setPlaybackPositionUpdateListener(this, handler);
         }
 
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        if (mMakeSomething != null) {
-            mMakeSomething.join();
+        public synchronized void onMarkerReached(AudioTrack track) {
+            if (mIsTestActive) {
+                int position = mAudioTrack.getPlaybackHeadPosition();
+                mOnMarkerReachedCalled.add(position);
+                mMarkerPosition += mMarkerPeriodInFrames;
+                if (mMarkerPosition <= mFrameCount) {
+                    assertEquals(AudioTrack.SUCCESS,
+                            mAudioTrack.setNotificationMarkerPosition(mMarkerPosition));
+                }
+            } else {
+                fail("onMarkerReached called when not active");
+            }
         }
-        if (mAudioTrack != null) {
-            mAudioTrack.release();
+
+        public synchronized void onPeriodicNotification(AudioTrack track) {
+            if (mIsTestActive) {
+                mOnPeriodicNotificationCalled.add(mAudioTrack.getPlaybackHeadPosition());
+            } else {
+                fail("onPeriodicNotification called when not active");
+            }
+        }
+
+        public synchronized void stop() {
+            mIsTestActive = false;
+        }
+
+        public ArrayList<Integer> getMarkerList() {
+            return mOnMarkerReachedCalled;
+        }
+
+        public ArrayList<Integer> getPeriodicList() {
+            return mOnPeriodicNotificationCalled;
+        }
+
+        public synchronized void release() {
+            mAudioTrack.setPlaybackPositionUpdateListener(null);
             mAudioTrack = null;
         }
-        super.tearDown();
-    }
 
+        private boolean mIsTestActive = true;
+        private AudioTrack mAudioTrack;
+        private ArrayList<Integer> mOnMarkerReachedCalled = new ArrayList<Integer>();
+        private ArrayList<Integer> mOnPeriodicNotificationCalled = new ArrayList<Integer>();
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
index c837d0a..02276bc 100644
--- a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
@@ -320,9 +320,6 @@
      * Tests clear key system playback.
      */
     public void testClearKeyPlayback() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
 
         MediaDrm drm = startDrm();
         if (null == drm) {
diff --git a/tests/tests/media/src/android/media/cts/EqualizerTest.java b/tests/tests/media/src/android/media/cts/EqualizerTest.java
index 15f0c73..f07c99e 100644
--- a/tests/tests/media/src/android/media/cts/EqualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/EqualizerTest.java
@@ -49,9 +49,6 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         Equalizer eq = null;
         try {
             eq = new Equalizer(0, 0);
@@ -78,9 +75,6 @@
 
     //Test case 1.0: test setBandLevel() and getBandLevel()
     public void test1_0BandLevel() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getEqualizer(0);
         try {
             short numBands = mEqualizer.getNumberOfBands();
@@ -110,9 +104,6 @@
 
     //Test case 1.1: test band frequency
     public void test1_1BandFrequency() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getEqualizer(0);
         try {
             short band = mEqualizer.getBand(TEST_FREQUENCY_MILLIHERTZ);
@@ -138,9 +129,6 @@
 
     //Test case 1.2: test presets
     public void test1_2Presets() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getEqualizer(0);
         try {
             short numPresets = mEqualizer.getNumberOfPresets();
@@ -166,9 +154,6 @@
 
     //Test case 1.3: test properties
     public void test1_3Properties() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getEqualizer(0);
         try {
             Equalizer.Settings settings = mEqualizer.getProperties();
@@ -200,9 +185,6 @@
 
     //Test case 1.4: test setBandLevel() throws exception after release
     public void test1_4SetBandLevelAfterRelease() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getEqualizer(0);
         mEqualizer.release();
         try {
@@ -220,9 +202,6 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getEqualizer(0);
         try {
             mEqualizer.setEnabled(true);
@@ -239,9 +218,6 @@
 
     //Test case 2.1: test setEnabled() throws exception after release
     public void test2_1SetEnabledAfterRelease() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getEqualizer(0);
         mEqualizer.release();
         try {
@@ -259,9 +235,6 @@
 
     //Test case 3.0: test control status listener
     public void test3_0ControlStatusListener() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         synchronized(mLock) {
             mHasControl = true;
             mInitialized = false;
@@ -284,9 +257,6 @@
 
     //Test case 3.1: test enable status listener
     public void test3_1EnableStatusListener() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, true, false);
@@ -311,9 +281,6 @@
 
     //Test case 3.2: test parameter changed listener
     public void test3_2ParameterChangedListener() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, false, true);
diff --git a/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java b/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java
index be5099e..c19102b 100644
--- a/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java
+++ b/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java
@@ -43,9 +43,6 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
         assertNotNull("null AudioManager", am);
         getLoudnessEnhancer(0);
@@ -63,9 +60,6 @@
 
     //Test case 1.0: test set/get target gain
     public void test1_0TargetGain() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getLoudnessEnhancer(0);
         try {
             mLE.setTargetGain(0);
diff --git a/tests/tests/media/src/android/media/cts/MediaDrmMockTest.java b/tests/tests/media/src/android/media/cts/MediaDrmMockTest.java
index 1a3184d..52fd395 100644
--- a/tests/tests/media/src/android/media/cts/MediaDrmMockTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaDrmMockTest.java
@@ -19,6 +19,7 @@
 import android.media.MediaDrm;
 import android.media.MediaDrm.ProvisionRequest;
 import android.media.MediaDrm.KeyRequest;
+import android.media.MediaDrm.KeyStatus;
 import android.media.MediaDrm.CryptoSession;
 import android.media.MediaDrmException;
 import android.media.NotProvisionedException;
@@ -231,6 +232,7 @@
         md.setPropertyByteArray("mock-request", testRequest);
         String testDefaultUrl = "http://1.2.3.4:8080/blah";
         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
+        md.setPropertyString("mock-keyRequestType", "1" /*kKeyRequestType_Initial*/);
 
         byte[] initData = {0x0a, 0x0b, 0x0c, 0x0d};
         HashMap<String, String> optionalParameters = new HashMap<String, String>();
@@ -243,6 +245,7 @@
                                                       optionalParameters);
         assertTrue(Arrays.equals(request.getData(), testRequest));
         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
+        assertEquals(request.getRequestType(), MediaDrm.REQUEST_TYPE_INITIAL);
 
         assertTrue(Arrays.equals(initData, md.getPropertyByteArray("mock-initdata")));
         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
@@ -265,6 +268,7 @@
         md.setPropertyByteArray("mock-request", testRequest);
         String testDefaultUrl = "http://1.2.3.4:8080/blah";
         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
+        md.setPropertyString("mock-keyRequestType", "1" /*kKeyRequestType_Initial*/);
 
         byte[] initData = {0x0a, 0x0b, 0x0c, 0x0d};
 
@@ -274,6 +278,7 @@
                                                       null);
         assertTrue(Arrays.equals(request.getData(), testRequest));
         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
+        assertEquals(request.getRequestType(), MediaDrm.REQUEST_TYPE_INITIAL);
 
         assertTrue(Arrays.equals(initData, md.getPropertyByteArray("mock-initdata")));
         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
@@ -295,6 +300,7 @@
         md.setPropertyByteArray("mock-request", testRequest);
         String testDefaultUrl = "http://1.2.3.4:8080/blah";
         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
+        md.setPropertyString("mock-keyRequestType", "2" /*kKeyRequestType_Renewal*/);
 
         byte[] initData = {0x0a, 0x0b, 0x0c, 0x0d};
 
@@ -304,6 +310,7 @@
                                               null);
         assertTrue(Arrays.equals(request.getData(), testRequest));
         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
+        assertEquals(request.getRequestType(), MediaDrm.REQUEST_TYPE_RENEWAL);
 
         assertTrue(Arrays.equals(initData, md.getPropertyByteArray("mock-initdata")));
         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
@@ -325,6 +332,7 @@
         md.setPropertyByteArray("mock-request", testRequest);
         String testDefaultUrl = "http://1.2.3.4:8080/blah";
         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
+        md.setPropertyString("mock-keyRequestType", "3" /*kKeyRequestType_Release*/);
 
         String mimeType = "video/iso.segment";
         KeyRequest request = md.getKeyRequest(sessionId, null, mimeType,
@@ -332,6 +340,7 @@
                                               null);
         assertTrue(Arrays.equals(request.getData(), testRequest));
         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
+        assertEquals(request.getRequestType(), MediaDrm.REQUEST_TYPE_RELEASE);
 
         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
         assertTrue(md.getPropertyString("mock-keytype").equals("2"));
@@ -780,6 +789,170 @@
         assertTrue(mGotEvent);
     }
 
+    public void testExpirationUpdate() throws Exception {
+        if (!isMockPluginInstalled()) {
+            return;
+        }
+
+
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by mMediaPlayer.
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                try {
+                    mMediaDrm = new MediaDrm(mockScheme);
+                } catch (MediaDrmException e) {
+                    e.printStackTrace();
+                    fail();
+                }
+
+
+                final byte[] expected_sessionId = openSession(mMediaDrm);
+
+                mMediaDrm.setPropertyByteArray("mock-event-session-id", expected_sessionId);
+
+                synchronized(mLock) {
+                    mLock.notify();
+
+                    mMediaDrm.setOnExpirationUpdateListener(new MediaDrm.OnExpirationUpdateListener() {
+                            @Override
+                            public void onExpirationUpdate(MediaDrm md, byte[] sessionId,
+                                    long expiryTimeMS) {
+                                synchronized(mLock) {
+                                    Log.d(TAG,"testExpirationUpdate.onExpirationUpdate");
+                                    assertTrue(md == mMediaDrm);
+                                    assertTrue(Arrays.equals(sessionId, expected_sessionId));
+                                    assertTrue(expiryTimeMS == 123456789012345L);
+                                    mGotEvent = true;
+                                    mLock.notify();
+                                }
+                            }
+                        }, null);
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+
+        // wait for mMediaDrm to be created
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch (Exception e) {
+            }
+        }
+        assertTrue(mMediaDrm != null);
+
+        mGotEvent = false;
+        mMediaDrm.setPropertyString("mock-send-expiration-update", "123456789012345");
+
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch (Exception e) {
+            }
+        }
+
+        mLooper.quit();
+        assertTrue(mGotEvent);
+    }
+
+    public void testKeysChange() throws Exception {
+        if (!isMockPluginInstalled()) {
+            return;
+        }
+
+
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by mMediaPlayer.
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                try {
+                    mMediaDrm = new MediaDrm(mockScheme);
+                } catch (MediaDrmException e) {
+                    e.printStackTrace();
+                    fail();
+                }
+
+
+                final byte[] expected_sessionId = openSession(mMediaDrm);
+
+                mMediaDrm.setPropertyByteArray("mock-event-session-id", expected_sessionId);
+
+                synchronized(mLock) {
+                    mLock.notify();
+
+                    mMediaDrm.setOnKeysChangeListener(new MediaDrm.OnKeysChangeListener() {
+                            @Override
+                            public void onKeysChange(MediaDrm md, byte[] sessionId,
+                                    List<KeyStatus> keyInformation, boolean hasNewUsableKey) {
+                                synchronized(mLock) {
+                                    Log.d(TAG,"testKeysChange.onKeysChange");
+                                    assertTrue(md == mMediaDrm);
+                                    assertTrue(Arrays.equals(sessionId, expected_sessionId));
+                                    try {
+                                        KeyStatus keyStatus = keyInformation.get(0);
+                                        assertTrue(Arrays.equals(keyStatus.getKeyId(), "key1".getBytes()));
+                                        assertTrue(keyStatus.getStatusCode() == MediaDrm.KEY_STATUS_USABLE);
+                                        keyStatus = keyInformation.get(1);
+                                        assertTrue(Arrays.equals(keyStatus.getKeyId(), "key2".getBytes()));
+                                        assertTrue(keyStatus.getStatusCode() == MediaDrm.KEY_STATUS_EXPIRED);
+                                        keyStatus = keyInformation.get(2);
+                                        assertTrue(Arrays.equals(keyStatus.getKeyId(), "key3".getBytes()));
+                                        assertTrue(keyStatus.getStatusCode() == MediaDrm.KEY_STATUS_OUTPUT_NOT_ALLOWED);
+                                        keyStatus = keyInformation.get(3);
+                                        assertTrue(Arrays.equals(keyStatus.getKeyId(), "key4".getBytes()));
+                                        assertTrue(keyStatus.getStatusCode() == MediaDrm.KEY_STATUS_PENDING);
+                                        keyStatus = keyInformation.get(4);
+                                        assertTrue(Arrays.equals(keyStatus.getKeyId(), "key5".getBytes()));
+                                        assertTrue(keyStatus.getStatusCode() == MediaDrm.KEY_STATUS_INTERNAL_ERROR);
+                                        assertTrue(hasNewUsableKey);
+                                        mGotEvent = true;
+                                    } catch (IndexOutOfBoundsException e) {
+                                    }
+                                    mLock.notify();
+                                }
+                            }
+                        }, null);
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+
+        // wait for mMediaDrm to be created
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch (Exception e) {
+            }
+        }
+        assertTrue(mMediaDrm != null);
+
+        mGotEvent = false;
+        mMediaDrm.setPropertyString("mock-send-keys-change", "123456789012345");
+
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch (Exception e) {
+            }
+        }
+
+        mLooper.quit();
+        assertTrue(mGotEvent);
+    }
+
     private byte[] openSession(MediaDrm md) {
         byte[] sessionId = null;
         try {
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index e058981..47467ac 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -348,10 +348,6 @@
     }
 
     public void testPlayAudioTwice() throws Exception {
-        if (!hasAudioOutput()) {
-            Log.i(LOG_TAG, "SKIPPING testPlayAudioTwice(). No audio output.");
-            return;
-        }
 
         final int resid = R.raw.camera_click;
 
@@ -599,10 +595,6 @@
     }
 
     private void testGapless(int resid1, int resid2) throws Exception {
-        if (!hasAudioOutput()) {
-            Log.i(LOG_TAG, "SKIPPING testPlayAudioTwice(). No audio output.");
-            return;
-        }
 
         MediaPlayer mp1 = new MediaPlayer();
         mp1.setAudioStreamType(AudioManager.STREAM_MUSIC);
@@ -838,6 +830,36 @@
         assertEquals(Integer.parseInt(rotation), angle);
     }
 
+    public void testPlaybackRate() throws Exception {
+        final int toleranceMs = 1000;
+        if (!checkLoadResource(
+                R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) {
+            return; // skip
+        }
+
+        mMediaPlayer.prepare();
+        float[] rates = { 0.25f, 0.5f, 1.0f, 2.0f };
+        for (float playbackRate : rates) {
+            mMediaPlayer.seekTo(0);
+            Thread.sleep(1000);
+            int playTime = 4000;  // The testing clip is about 10 second long.
+            mMediaPlayer.setPlaybackRate(playbackRate,
+                                         MediaPlayer.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE);
+            mMediaPlayer.start();
+            Thread.sleep(playTime);
+            assertTrue("MediaPlayer should still be playing", mMediaPlayer.isPlaying());
+
+            int playedMediaDurationMs = mMediaPlayer.getCurrentPosition();
+            int diff = Math.abs((int)(playedMediaDurationMs / playbackRate) - playTime);
+            if (diff > toleranceMs) {
+                fail("Media player had error in playback rate " + playbackRate
+                     + ", play time is " + playTime + " vs expected " + playedMediaDurationMs);
+            }
+            mMediaPlayer.pause();
+        }
+        mMediaPlayer.stop();
+    }
+
     public void testLocalVideo_MP4_H264_480x360_500kbps_25fps_AAC_Stereo_128kbps_44110Hz()
             throws Exception {
         playVideoTest(
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
index d089658e..b7283db 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
@@ -294,11 +294,6 @@
 
     private static class PrepareFailedException extends Exception {}
 
-    public boolean hasAudioOutput() {
-        return getInstrumentation().getTargetContext().getPackageManager()
-            .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
-    }
-
     public boolean isTv() {
         PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
         return pm.hasSystemFeature(pm.FEATURE_TELEVISION)
diff --git a/tests/tests/media/src/android/media/cts/PostProcTestBase.java b/tests/tests/media/src/android/media/cts/PostProcTestBase.java
index ef87662..cefbbf4 100644
--- a/tests/tests/media/src/android/media/cts/PostProcTestBase.java
+++ b/tests/tests/media/src/android/media/cts/PostProcTestBase.java
@@ -40,30 +40,18 @@
     }
 
     protected boolean isBassBoostAvailable() {
-        if (!hasAudioOutput()) {
-            return false;
-        }
         return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_BASS_BOOST);
     }
 
     protected boolean isVirtualizerAvailable() {
-        if (!hasAudioOutput()) {
-            return false;
-        }
         return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_VIRTUALIZER);
     }
 
     protected boolean isPresetReverbAvailable() {
-        if (!hasAudioOutput()) {
-            return false;
-        }
         return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_PRESET_REVERB);
     }
 
     protected boolean isEnvReverbAvailable() {
-        if (!hasAudioOutput()) {
-            return false;
-        }
         return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_ENV_REVERB);
     }
 
diff --git a/tests/tests/media/src/android/media/cts/VisualizerTest.java b/tests/tests/media/src/android/media/cts/VisualizerTest.java
index 3c639a0..0d46ca7 100644
--- a/tests/tests/media/src/android/media/cts/VisualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VisualizerTest.java
@@ -55,9 +55,6 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         Visualizer visualizer = null;
         try {
             visualizer = new Visualizer(0);
@@ -79,9 +76,6 @@
 
     //Test case 1.0: capture rates
     public void test1_0CaptureRates() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getVisualizer(0);
         try {
             int captureRate = mVisualizer.getMaxCaptureRate();
@@ -101,9 +95,6 @@
 
     //Test case 1.1: test capture size
     public void test1_1CaptureSize() throws Exception {
-        if (!hasAudioOutput()) {
-            return;
-        }
         getVisualizer(0);
         try {
             int[] range = mVisualizer.getCaptureSizeRange();
@@ -135,6 +126,8 @@
     //Test case 2.0: test capture in polling mode
     public void test2_0PollingCapture() throws Exception {
         if (!hasAudioOutput()) {
+            Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
+                    + "audio output HAL");
             return;
         }
         try {
@@ -165,6 +158,8 @@
     //Test case 2.1: test capture with listener
     public void test2_1ListenerCapture() throws Exception {
         if (!hasAudioOutput()) {
+            Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
+                    + "audio output HAL");
             return;
         }
         try {
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index f6e5c90..a35e145 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -24,7 +24,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_JAVA_LIBRARIES := voip-common conscrypt
+LOCAL_JAVA_LIBRARIES := voip-common conscrypt org.apache.http.legacy
 
 LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni
 
diff --git a/tests/tests/net/AndroidManifest.xml b/tests/tests/net/AndroidManifest.xml
index 652262d..bca2d2c 100644
--- a/tests/tests/net/AndroidManifest.xml
+++ b/tests/tests/net/AndroidManifest.xml
@@ -30,6 +30,7 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/openglperf/Android.mk b/tests/tests/openglperf/Android.mk
index 7be16e8..6b42ed0 100644
--- a/tests/tests/openglperf/Android.mk
+++ b/tests/tests/openglperf/Android.mk
@@ -38,4 +38,10 @@
 
 include $(BUILD_CTS_PACKAGE)
 
+# Make the replica island app and copy it to CTS out dir.
+cts_replica_name := com.replica.replicaisland
+cts_replica_apk := $(CTS_TESTCASES_OUT)/$(cts_replica_name).apk
+$(cts_replica_apk): $(call intermediates-dir-for,APPS,$(cts_replica_name))/package.apk
+	$(call copy-file-to-target)
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 8a9b340..6069ee6 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -28,9 +28,8 @@
 public class BuildVersionTest extends TestCase {
 
     private static final String LOG_TAG = "BuildVersionTest";
-    private static final Set<String> EXPECTED_RELEASES =
-            new HashSet<String>(Arrays.asList("5.1"));
-    private static final int EXPECTED_SDK = 22;
+    private static final Set<String> EXPECTED_RELEASES = new HashSet<String>(Arrays.asList("5.0"));
+    private static final int EXPECTED_SDK = 21;
     private static final String EXPECTED_BUILD_VARIANT = "user";
     private static final String EXPECTED_TAG = "release-keys";
 
diff --git a/tests/tests/os/src/android/os/cts/LooperTest.java b/tests/tests/os/src/android/os/cts/LooperTest.java
index 79a55c6..6f7cb6d 100644
--- a/tests/tests/os/src/android/os/cts/LooperTest.java
+++ b/tests/tests/os/src/android/os/cts/LooperTest.java
@@ -78,6 +78,21 @@
         t.runTest(WAIT_TIME);
     }
 
+    public void testIsCurrentThread() throws Throwable {
+        final Looper[] looper = new Looper[1];
+        TestThread t = new TestThread(new Runnable() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                assertTrue(Looper.myLooper().isCurrentThread());
+                looper[0] = Looper.myLooper();
+            }
+        });
+
+        t.runTest(WAIT_TIME);
+        assertFalse(looper[0].isCurrentThread());
+    }
+
     public void testMyQueue() throws Throwable {
         TestThread t = new TestThread(new Runnable() {
             public void run() {
@@ -96,6 +111,18 @@
         t.runTest(WAIT_TIME);
     }
 
+    public void testGetQueue() throws Throwable {
+        TestThread t = new TestThread(new Runnable() {
+            public void run() {
+                Looper.prepare();
+                assertNotNull(Looper.myLooper().getQueue());
+                assertEquals(Looper.myLooper().getQueue(), Looper.myQueue());
+            }
+        });
+
+        t.runTest(WAIT_TIME);
+    }
+
     public void testPrepare() throws Throwable {
         TestThread t = new TestThread(new Runnable() {
             public void run() {
diff --git a/tests/tests/os/src/android/os/cts/MessageQueueTest.java b/tests/tests/os/src/android/os/cts/MessageQueueTest.java
index 5b5bf5c..f5d6415 100644
--- a/tests/tests/os/src/android/os/cts/MessageQueueTest.java
+++ b/tests/tests/os/src/android/os/cts/MessageQueueTest.java
@@ -16,16 +16,23 @@
 
 package android.os.cts;
 
-
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
+import android.os.MessageQueue.FileDescriptorCallback;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseInputStream;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
 import android.os.SystemClock;
 import android.os.MessageQueue.IdleHandler;
 import android.test.AndroidTestCase;
 
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -113,6 +120,48 @@
         }
     }
 
+    public void testIsIdle() throws Exception {
+        HandlerThread thread = new HandlerThread("testIsIdle");
+        thread.start();
+        try {
+            // Queue should initially be idle.
+            assertTrue(thread.getLooper().getQueue().isIdle());
+
+            // Post two messages.  Block in the first one leaving the second one pending.
+            final CountDownLatch latch1 = new CountDownLatch(1);
+            final CountDownLatch latch2 = new CountDownLatch(1);
+            Handler handler = new Handler(thread.getLooper());
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    // Wait for latch1 released before returning.
+                    try {
+                        latch1.await(TIMEOUT, TimeUnit.MILLISECONDS);
+                    } catch (InterruptedException ex) { }
+                }
+            });
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    // Release latch2 when finished.
+                    latch2.countDown();
+                }
+            });
+
+            // The first message is blocked so the second should still be in the queue.
+            // At this point the queue will not be idle because there is a pending message.
+            assertFalse(thread.getLooper().getQueue().isIdle());
+
+            // Let the first message complete and wait for the second to leave the queue.
+            // At this point the queue will be idle because it is empty.
+            latch1.countDown();
+            latch2.await(TIMEOUT, TimeUnit.MILLISECONDS);
+            assertTrue(thread.getLooper().getQueue().isIdle());
+        } finally {
+            thread.quitSafely();
+        }
+    }
+
     /**
      * Use MessageQueue, send message by order
      */
@@ -162,6 +211,514 @@
         tester.doTest(1000, 50);
     }
 
+    public void testRegisterFileDescriptorCallbackThrowsWhenFdIsNull() {
+        MessageQueue queue = Looper.getMainLooper().getQueue();
+        try {
+            queue.registerFileDescriptorCallback(null, 0,
+                    new FileDescriptorCallback() { });
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException ex) {
+            // expected
+        }
+    }
+
+    public void testRegisterFileDescriptorCallbackThrowsWhenCallbackIsNull() throws Exception {
+        MessageQueue queue = Looper.getMainLooper().getQueue();
+        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+        try (ParcelFileDescriptor reader = pipe[0];
+                ParcelFileDescriptor writer = pipe[1]) {
+            try {
+                queue.registerFileDescriptorCallback(reader.getFileDescriptor(), 0, null);
+                fail("Expected IllegalArgumentException");
+            } catch (IllegalArgumentException ex) {
+                // expected
+            }
+        }
+    }
+
+    public void testUnregisterFileDescriptorCallbackThrowsWhenFdIsNull() throws Exception {
+        MessageQueue queue = Looper.getMainLooper().getQueue();
+        try {
+            queue.unregisterFileDescriptorCallback(null);
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException ex) {
+            // expected
+        }
+    }
+
+    public void testUnregisterFileDescriptorCallbackDoesNothingWhenFdNotRegistered()
+            throws Exception {
+        MessageQueue queue = Looper.getMainLooper().getQueue();
+        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+        try (ParcelFileDescriptor reader = pipe[0];
+                ParcelFileDescriptor writer = pipe[1]) {
+            queue.unregisterFileDescriptorCallback(reader.getFileDescriptor());
+        }
+    }
+
+    public void testFileDescriptorCallbacks() throws Throwable {
+        // Prepare a special looper that we can catch exceptions from.
+        AssertableHandlerThread thread = new AssertableHandlerThread();
+        thread.start();
+        try {
+            final CountDownLatch writerSawError = new CountDownLatch(1);
+            final CountDownLatch readerDone = new CountDownLatch(1);
+            final MessageQueue queue = thread.getLooper().getQueue();
+            final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+            try (final FileInputStream reader = new AutoCloseInputStream(pipe[0]);
+                    final FileOutputStream writer = new AutoCloseOutputStream(pipe[1])) {
+                final int size = 256 * 1024;
+
+                // Prepare to write a lot of data to the pipe asynchronously.
+                // We don't actually care about the content (assume pipes work correctly)
+                // so we just write lots of zeros.
+                FileDescriptorCallback writerCallback = new FileDescriptorCallback() {
+                    private byte[] mBuffer = new byte[4096];
+                    private int mRemaining = size;
+                    private boolean mDone;
+
+                    @Override
+                    public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                        assertEquals(pipe[1].getFileDescriptor(), fd);
+                        if (!mDone) {
+                            // When an error happens because the reader closed its end,
+                            // signal the test, and remove the callback.
+                            if ((events & FileDescriptorCallback.EVENT_ERROR) != 0) {
+                                writerSawError.countDown();
+                                mDone = true;
+                                return 0;
+                            }
+
+                            // Write all output until an error is observed.
+                            if ((events & FileDescriptorCallback.EVENT_OUTPUT) != 0) {
+                                int count = Math.min(mBuffer.length, mRemaining);
+                                try {
+                                    writer.write(mBuffer, 0, count);
+                                } catch (IOException ex) {
+                                    throw new RuntimeException(ex);
+                                }
+                                mRemaining -= count;
+                                return mRemaining != 0 ? EVENT_OUTPUT : EVENT_ERROR;
+                            }
+                        }
+
+                        // Should never see anything else.
+                        fail("Saw unexpected events: " + events + ", mDone=" + mDone);
+                        return 0;
+                    }
+                };
+
+                // Prepare to read all of that data.
+                FileDescriptorCallback readerCallback = new FileDescriptorCallback() {
+                    private byte[] mBuffer = new byte[4096];
+                    private int mRemaining = size;
+                    private boolean mDone;
+
+                    @Override
+                    public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                        assertEquals(pipe[0].getFileDescriptor(), fd);
+                        if (!mDone) {
+                            // Errors should not happen.
+                            if ((events & FileDescriptorCallback.EVENT_ERROR) != 0) {
+                                fail("Saw unexpected error.");
+                                return 0;
+                            }
+
+                            // Read until everything is read, signal the test,
+                            // and remove the callback.
+                            if ((events & FileDescriptorCallback.EVENT_INPUT) != 0) {
+                                try {
+                                    int count = reader.read(mBuffer, 0, mBuffer.length);
+                                    mRemaining -= count;
+                                } catch (IOException ex) {
+                                    throw new RuntimeException(ex);
+                                }
+                                if (mRemaining != 0) {
+                                    return EVENT_INPUT;
+                                }
+                                readerDone.countDown();
+                                mDone = true;
+                                return 0;
+                            }
+                        }
+
+                        // Should never see anything else.
+                        fail("Saw unexpected events: " + events + ", mDone=" + mDone);
+                        return 0;
+                    }
+                };
+
+                // Register the callbacks.
+                queue.registerFileDescriptorCallback(reader.getFD(),
+                        FileDescriptorCallback.EVENT_INPUT, readerCallback);
+                queue.registerFileDescriptorCallback(writer.getFD(),
+                        FileDescriptorCallback.EVENT_OUTPUT, writerCallback);
+
+                // Wait for the reader to see all of the data that the writer
+                // is prepared to send.
+                readerDone.await(TIMEOUT, TimeUnit.MILLISECONDS);
+
+                // At this point the reader's callback should be unregistered.
+                // Close the reader's file descriptor (pretend it crashed or something).
+                reader.close();
+
+                // Because the reader is gone, the writer should observe an error (EPIPE).
+                // Wait for this to happen.
+                writerSawError.await(TIMEOUT, TimeUnit.MILLISECONDS);
+
+                // The reader and writer should already be unregistered.
+                // Try to unregistered them again to ensure nothing bad happens.
+                queue.unregisterFileDescriptorCallback(reader.getFD());
+                queue.unregisterFileDescriptorCallback(writer.getFD());
+            }
+        } finally {
+            thread.quitAndRethrow();
+        }
+    }
+
+    /**
+     * Since file descriptor numbers may be reused, there are some interesting
+     * edge cases around closing file descriptors within the callback and adding
+     * new ones with the same number.
+     *
+     * Register a file descriptor, close it from within the callback before
+     * returning, return.  Then create a new file descriptor (with the same number),
+     * register it.  Ensure that we start getting events for the new file descriptor.
+     *
+     * This test exercises special logic in Looper.cpp for EPOLL_CTL_DEL handling EBADF.
+     */
+    public void testPathologicalFileDescriptorReuseCallbacks1() throws Throwable {
+        // Prepare a special looper that we can catch exceptions from.
+        AssertableHandlerThread thread = new AssertableHandlerThread();
+        thread.start();
+        try {
+            final MessageQueue queue = thread.getLooper().getQueue();
+            final Handler handler = new Handler(thread.getLooper());
+
+            final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+            final int oldReaderFd = pipe[0].getFd();
+            try (final FileInputStream reader = new AutoCloseInputStream(pipe[0]);
+                    final FileOutputStream writer = new AutoCloseOutputStream(pipe[1])) {
+                // Register the callback.
+                final boolean[] awoke = new boolean[1];
+                queue.registerFileDescriptorCallback(reader.getFD(),
+                        FileDescriptorCallback.EVENT_ERROR, new FileDescriptorCallback() {
+                    @Override
+                    public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                        awoke[0] = true;
+
+                        // Close the file descriptor before we return.
+                        try {
+                            reader.close();
+                        } catch (IOException ex) {
+                            throw new RuntimeException(ex);
+                        }
+
+                        // Return 0 to unregister the callback.
+                        return 0;
+                    }
+                });
+
+                // Close the writer to wake up the callback (due to hangup).
+                writer.close();
+
+                // Wait for the looper to catch up and run the callback.
+                syncWait(handler);
+                assertTrue(awoke[0]);
+            }
+
+            // At this point, the reader and writer are both closed.
+            // If we're lucky, we can create a new pipe with the same file
+            // descriptor numbers as before.
+            final ParcelFileDescriptor[] pipe2 = ParcelFileDescriptor.createPipe();
+            assertEquals("Expected new pipe to be created with same fd number as "
+                    + "previous pipe we just closed for the purpose of this test.",
+                    oldReaderFd, pipe2[0].getFd());
+            try (final FileInputStream reader2 = new AutoCloseInputStream(pipe2[0]);
+                    final FileOutputStream writer2 = new AutoCloseOutputStream(pipe2[1])) {
+                // Register the callback.
+                final boolean[] awoke = new boolean[1];
+                queue.registerFileDescriptorCallback(reader2.getFD(),
+                        FileDescriptorCallback.EVENT_INPUT, new FileDescriptorCallback() {
+                    @Override
+                    public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                        awoke[0] = true;
+
+                        // Return 0 to unregister the callback.
+                        return 0;
+                    }
+                });
+
+                // Close the writer to wake up the callback (due to hangup).
+                writer2.close();
+
+                // Wait for the looper to catch up and run the callback.
+                syncWait(handler);
+                assertTrue(awoke[0]);
+            }
+        } finally {
+            thread.quitAndRethrow();
+        }
+    }
+
+    /**
+     * Since file descriptor numbers may be reused, there are some interesting
+     * edge cases around closing file descriptors within the callback and adding
+     * new ones with the same number.
+     *
+     * Register a file descriptor, close it from within the callback before
+     * returning, create a new file descriptor (with the same number) and return.
+     * Then register the same file descriptor.  Ensure that we start getting events for
+     * the new file descriptor.
+     *
+     * This test exercises special logic in Looper.cpp for EPOLL_CTL_DEL handling ENOENT.
+     */
+    public void testPathologicalFileDescriptorReuseCallbacks2() throws Throwable {
+        // Prepare a special looper that we can catch exceptions from.
+        AssertableHandlerThread thread = new AssertableHandlerThread();
+        thread.start();
+        try {
+            final MessageQueue queue = thread.getLooper().getQueue();
+            final Handler handler = new Handler(thread.getLooper());
+
+            final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+            final int oldReaderFd = pipe[0].getFd();
+            try (final FileInputStream reader = new AutoCloseInputStream(pipe[0]);
+                    final FileOutputStream writer = new AutoCloseOutputStream(pipe[1])) {
+                // Register the callback.
+                final boolean[] awoke = new boolean[1];
+                queue.registerFileDescriptorCallback(reader.getFD(),
+                        FileDescriptorCallback.EVENT_ERROR, new FileDescriptorCallback() {
+                    @Override
+                    public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                        awoke[0] = true;
+
+                        try {
+                            // Close the file descriptor before we return.
+                            reader.close();
+
+                            // At this point, the reader and writer are both closed.
+                            // Assuming no one else has created a file descriptor in the meantime,
+                            // when we recreate the pipe we will get the same number as before.
+                            final ParcelFileDescriptor[] pipe2 = ParcelFileDescriptor.createPipe();
+                            assertEquals("Expected new pipe to be created with same fd number as "
+                                    + "previous pipe we just closed for the purpose of this test.",
+                                    oldReaderFd, pipe2[0].getFd());
+                            pipe[0] = pipe2[0];
+                            pipe[1] = pipe2[1];
+                        } catch (IOException ex) {
+                            throw new RuntimeException(ex);
+                        }
+
+                        // Return 0 to unregister the callback.
+                        return 0;
+                    }
+                });
+
+                // Close the writer to wake up the callback (due to hangup).
+                writer.close();
+
+                // Wait for the looper to catch up and run the callback.
+                syncWait(handler);
+                assertTrue(awoke[0]);
+            }
+
+            // Now we have a new pipe, make sure we can register it successfully.
+            try (final FileInputStream reader2 = new AutoCloseInputStream(pipe[0]);
+                    final FileOutputStream writer2 = new AutoCloseOutputStream(pipe[1])) {
+                // Register the callback.
+                final boolean[] awoke = new boolean[1];
+                queue.registerFileDescriptorCallback(reader2.getFD(),
+                        FileDescriptorCallback.EVENT_INPUT, new FileDescriptorCallback() {
+                    @Override
+                    public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                        awoke[0] = true;
+
+                        // Return 0 to unregister the callback.
+                        return 0;
+                    }
+                });
+
+                // Close the writer to wake up the callback (due to hangup).
+                writer2.close();
+
+                // Wait for the looper to catch up and run the callback.
+                syncWait(handler);
+                assertTrue(awoke[0]);
+            }
+        } finally {
+            thread.quitAndRethrow();
+        }
+    }
+
+    /**
+     * Since file descriptor numbers may be reused, there are some interesting
+     * edge cases around closing file descriptors within the callback and adding
+     * new ones with the same number.
+     *
+     * Register a file descriptor, close it from within the callback before
+     * returning, create a new file descriptor (with the same number),
+     * register it, and return.  Ensure that we start getting events for the
+     * new file descriptor.
+     *
+     * This test exercises special logic in Looper.cpp for EPOLL_CTL_MOD handling
+     * ENOENT and fallback to EPOLL_CTL_ADD as well as sequence number checks when removing
+     * the fd after the callback returns.
+     */
+    public void testPathologicalFileDescriptorReuseCallbacks3() throws Throwable {
+        // Prepare a special looper that we can catch exceptions from.
+        AssertableHandlerThread thread = new AssertableHandlerThread();
+        thread.start();
+        try {
+            final MessageQueue queue = thread.getLooper().getQueue();
+            final Handler handler = new Handler(thread.getLooper());
+
+            final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+            final boolean[] awoke2 = new boolean[1];
+            final int oldReaderFd = pipe[0].getFd();
+            try (final FileInputStream reader = new AutoCloseInputStream(pipe[0]);
+                    final FileOutputStream writer = new AutoCloseOutputStream(pipe[1])) {
+                // Register the callback.
+                final boolean[] awoke = new boolean[1];
+                queue.registerFileDescriptorCallback(reader.getFD(),
+                        FileDescriptorCallback.EVENT_ERROR, new FileDescriptorCallback() {
+                    @Override
+                    public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                        awoke[0] = true;
+
+                        final ParcelFileDescriptor[] pipe2;
+                        try {
+                            // Close the file descriptor before we return.
+                            reader.close();
+
+                            // At this point, the reader and writer are both closed.
+                            // Assuming no one else has created a file descriptor in the meantime,
+                            // when we recreate the pipe we will get the same number as before.
+                            pipe2 = ParcelFileDescriptor.createPipe();
+                            assertEquals("Expected new pipe to be created with same fd number as "
+                                    + "previous pipe we just closed for the purpose of this test.",
+                                    oldReaderFd, pipe2[0].getFd());
+                            pipe[0] = pipe2[0];
+                            pipe[1] = pipe2[1];
+                        } catch (IOException ex) {
+                            throw new RuntimeException(ex);
+                        }
+
+                        // Now we have a new pipe, make sure we can register it successfully.
+                        queue.registerFileDescriptorCallback(pipe[0].getFileDescriptor(),
+                                FileDescriptorCallback.EVENT_INPUT,
+                                new FileDescriptorCallback() {
+                            @Override
+                            public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                                awoke2[0] = true;
+
+                                // Return 0 to unregister the callback.
+                                return 0;
+                            }
+                        });
+
+                        // Return 0 to unregister the callback.
+                        return 0;
+                    }
+                });
+
+                // Close the writer to wake up the callback (due to hangup).
+                writer.close();
+
+                // Wait for the looper to catch up and run the callback.
+                syncWait(handler);
+                assertTrue(awoke[0]);
+            }
+
+            // Close the second writer to wake up the second callback (due to hangup).
+            pipe[1].close();
+
+            // Wait for the looper to catch up and run the callback.
+            syncWait(handler);
+            assertTrue(awoke2[0]);
+
+            // Close the second reader now that we're done with the test.
+            pipe[0].close();
+        } finally {
+            thread.quitAndRethrow();
+        }
+    }
+
+    /**
+     * Since file descriptor numbers may be reused, there are some interesting
+     * edge cases around closing file descriptors within the callback and adding
+     * new ones with the same number.
+     *
+     * Register a file descriptor, make a duplicate of it, close it from within the
+     * callback before returning, return.  Look for signs that the Looper is spinning
+     * and never getting a chance to block.
+     *
+     * This test exercises special logic in Looper.cpp for rebuilding the epoll set
+     * in case it contains a file descriptor which has been closed and cannot be removed.
+     */
+    public void testPathologicalFileDescriptorReuseCallbacks4() throws Throwable {
+        // Prepare a special looper that we can catch exceptions from.
+        ParcelFileDescriptor dup = null;
+        AssertableHandlerThread thread = new AssertableHandlerThread();
+        thread.start();
+        try {
+            try {
+                final MessageQueue queue = thread.getLooper().getQueue();
+                final Handler handler = new Handler(thread.getLooper());
+
+                final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+                dup = pipe[0].dup();
+                try (final FileInputStream reader = new AutoCloseInputStream(pipe[0]);
+                        final FileOutputStream writer = new AutoCloseOutputStream(pipe[1])) {
+                    // Register the callback.
+                    final boolean[] awoke = new boolean[1];
+                    queue.registerFileDescriptorCallback(reader.getFD(),
+                            FileDescriptorCallback.EVENT_ERROR, new FileDescriptorCallback() {
+                        @Override
+                        public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                            awoke[0] = true;
+
+                            // Close the file descriptor before we return.
+                            try {
+                                reader.close();
+                            } catch (IOException ex) {
+                                throw new RuntimeException(ex);
+                            }
+
+                            // Return 0 to unregister the callback.
+                            return 0;
+                        }
+                    });
+
+                    // Close the writer to wake up the callback (due to hangup).
+                    writer.close();
+
+                    // Wait for the looper to catch up and run the callback.
+                    syncWait(handler);
+                    assertTrue(awoke[0]);
+                }
+
+                // Wait a little bit before we stop the thread.
+                Thread.sleep(2000);
+            } finally {
+                // Check for how long the thread was running.
+                // If the Looper behaved correctly, then it should have blocked for most of
+                // the duration of the test (including that sleep above) since not much else
+                // was happening.  If we failed to actually rebuild the epoll set then the
+                // Looper may have been spinning continuously due to an FD that was never
+                // properly removed from the epoll set so the thread runtime will be very high.
+                long runtime = thread.quitAndRethrow();
+                assertFalse("Looper thread spent most of its time spinning instead of blocked.",
+                        runtime > 1000);
+            }
+        } finally {
+            // Close the duplicate now that we are done with it.
+            if (dup != null) {
+                dup.close();
+            }
+        }
+    }
+
     public void testSyncBarriers() throws Exception {
         OrderTestHelper tester = new OrderTestHelper() {
             private int mBarrierToken1;
@@ -171,7 +728,7 @@
                 super.init();
                 mLastMessage = 10;
                 mHandler.sendEmptyMessage(0);
-                mBarrierToken1 = Looper.myLooper().postSyncBarrier();
+                mBarrierToken1 = Looper.myQueue().postSyncBarrier();
                 mHandler.sendEmptyMessage(5);
                 sendAsyncMessage(1);
                 sendAsyncMessage(2);
@@ -183,15 +740,15 @@
                 super.handleMessage(msg);
                 if (msg.what == 3) {
                     mHandler.sendEmptyMessage(7);
-                    mBarrierToken2 = Looper.myLooper().postSyncBarrier();
+                    mBarrierToken2 = Looper.myQueue().postSyncBarrier();
                     sendAsyncMessage(4);
                     sendAsyncMessage(8);
                 } else if (msg.what == 4) {
-                    Looper.myLooper().removeSyncBarrier(mBarrierToken1);
+                    Looper.myQueue().removeSyncBarrier(mBarrierToken1);
                     sendAsyncMessage(9);
                     mHandler.sendEmptyMessage(10);
                 } else if (msg.what == 8) {
-                    Looper.myLooper().removeSyncBarrier(mBarrierToken2);
+                    Looper.myQueue().removeSyncBarrier(mBarrierToken2);
                 }
             }
 
@@ -206,25 +763,38 @@
     }
 
     public void testReleaseSyncBarrierThrowsIfTokenNotValid() throws Exception {
+        MessageQueue queue = Looper.getMainLooper().getQueue();
+
         // Invalid token
         try {
-            Looper.getMainLooper().removeSyncBarrier(-1);
+            queue.removeSyncBarrier(-1);
             fail("Should have thrown IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
         }
 
         // Token already removed.
-        int barrierToken = Looper.getMainLooper().postSyncBarrier();
-        Looper.getMainLooper().removeSyncBarrier(barrierToken);
+        int barrierToken = queue.postSyncBarrier();
+        queue.removeSyncBarrier(barrierToken);
         try {
-            Looper.getMainLooper().removeSyncBarrier(barrierToken);
+            queue.removeSyncBarrier(barrierToken);
             fail("Should have thrown IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
         }
     }
 
+    private void syncWait(Handler handler) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        handler.post(new Runnable() {
+            @Override
+            public void run() {
+                latch.countDown();
+            }
+        });
+        latch.await(TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+
     /**
      * Helper class used to test sending message to message queue.
      */
@@ -328,4 +898,38 @@
             }
         }
     }
+
+    /**
+     * A HandlerThread that propagates exceptions out of the event loop
+     * instead of crashing the process.
+     */
+    private class AssertableHandlerThread extends HandlerThread {
+        private Throwable mThrowable;
+        private long mRuntime;
+
+        public AssertableHandlerThread() {
+            super("AssertableHandlerThread");
+        }
+
+        @Override
+        public void run() {
+            final long startTime = SystemClock.currentThreadTimeMillis();
+            try {
+                super.run();
+            } catch (Throwable t) {
+                mThrowable = t;
+            } finally {
+                mRuntime = SystemClock.currentThreadTimeMillis() - startTime;
+            }
+        }
+
+        public long quitAndRethrow() throws Throwable {
+            quitSafely();
+            join(TIMEOUT);
+            if (mThrowable != null) {
+                throw mThrowable;
+            }
+            return mRuntime;
+        }
+    }
 }
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
new file mode 100644
index 0000000..797f91f
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.cts;
+
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import libcore.io.Streams;
+
+import java.io.ByteArrayOutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Tests for {@link StrictMode}
+ */
+public class StrictModeTest extends AndroidTestCase {
+    private static final String TAG = "StrictModeTest";
+
+    private StrictMode.VmPolicy mPolicy;
+
+    @Override
+    protected void setUp() {
+        mPolicy = StrictMode.getVmPolicy();
+    }
+
+    @Override
+    protected void tearDown() {
+        StrictMode.setVmPolicy(mPolicy);
+    }
+
+    public void testCleartextNetwork() throws Exception {
+        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+                .detectCleartextNetwork()
+                .penaltyLog()
+                .build());
+
+        final long millis = System.currentTimeMillis();
+        final String msg = "Detected cleartext network traffic from UID "
+                + android.os.Process.myUid();
+
+        // Insecure connection should be detected
+        ((HttpURLConnection) new URL("http://android.com/").openConnection()).getResponseCode();
+
+        // Give system enough time to finish logging
+        SystemClock.sleep(5000);
+        assertTrue("Expected cleartext to be caught", readLogSince(millis).contains(msg));
+    }
+
+    public void testEncryptedNetwork() throws Exception {
+        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+                .detectCleartextNetwork()
+                .penaltyLog()
+                .build());
+
+        final long millis = System.currentTimeMillis();
+        final String msg = "Detected cleartext network traffic from UID "
+                + android.os.Process.myUid();
+
+        // Secure connection should be ignored
+        ((HttpURLConnection) new URL("https://android.com/").openConnection()).getResponseCode();
+
+        // Give system enough time to finish logging
+        SystemClock.sleep(5000);
+        assertFalse("Expected encrypted to be ignored", readLogSince(millis).contains(msg));
+    }
+
+    private String readLogSince(long millis) throws Exception {
+        final SimpleDateFormat format = new SimpleDateFormat("MM-DD HH:mm:ss.SSS");
+        final Process proc = new ProcessBuilder("logcat", "-t", format.format(new Date(millis)))
+                .redirectErrorStream(true).start();
+
+        final ByteArrayOutputStream buf = new ByteArrayOutputStream();
+        Streams.copy(proc.getInputStream(), buf);
+        final int res = proc.waitFor();
+
+        Log.d(TAG, "Log output was " + buf.size() + " bytes, exit code " + res);
+        return new String(buf.toByteArray());
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index f590f97..cc4742c 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -19,7 +19,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Environment;
+import android.system.Os;
 import android.system.OsConstants;
+import android.system.StructStatVfs;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -156,6 +158,7 @@
         assertFalse(f.canRead());
         assertFalse(f.canWrite());
         assertFalse(f.canExecute());
+        assertFalse(f.exists());
     }
 
     @MediumTest
@@ -251,6 +254,22 @@
     }
 
     @MediumTest
+    public void testProcSelfOomAdjSane() {
+        File f = new File("/proc/self/oom_adj");
+        assertTrue(f.canRead());
+        assertFalse(f.canWrite());
+        assertFalse(f.canExecute());
+    }
+
+    @MediumTest
+    public void testProcSelfOomScoreAdjSane() {
+        File f = new File("/proc/self/oom_score_adj");
+        assertTrue(f.canRead());
+        assertFalse(f.canWrite());
+        assertFalse(f.canExecute());
+    }
+
+    @MediumTest
     public void testTcpDefaultRwndSane() throws Exception {
         File f = new File("/proc/sys/net/ipv4/tcp_default_init_rwnd");
         assertTrue(f.canRead());
@@ -713,17 +732,20 @@
         return retval;
     }
 
-    public void testSystemMountedRO() throws IOException {
-        ParsedMounts pm = new ParsedMounts("/proc/self/mounts");
-        String mountPoint = pm.findMountPointContaining(new File("/system"));
-        assertTrue(mountPoint + " is not mounted read-only", pm.isMountReadOnly(mountPoint));
+    public void testSystemMountedRO() throws Exception {
+        StructStatVfs vfs = Os.statvfs("/system");
+        assertTrue("/system is not mounted read-only", (vfs.f_flag & OsConstants.ST_RDONLY) != 0);
     }
 
-    public void testRootMountedRO() throws IOException {
-        ParsedMounts pm = new ParsedMounts("/proc/self/mounts");
-        String mountPoint = pm.findMountPointContaining(new File("/"));
-        assertTrue("The root directory \"" + mountPoint + "\" is not mounted read-only",
-                   pm.isMountReadOnly(mountPoint));
+    public void testRootMountedRO() throws Exception {
+        StructStatVfs vfs = Os.statvfs("/");
+        assertTrue("rootfs is not mounted read-only", (vfs.f_flag & OsConstants.ST_RDONLY) != 0);
+    }
+
+    public void testDataMountedNoSuidNoDev() throws Exception {
+        StructStatVfs vfs = Os.statvfs(getContext().getFilesDir().getAbsolutePath());
+        assertTrue("/data is not mounted NOSUID", (vfs.f_flag & OsConstants.ST_NOSUID) != 0);
+        assertTrue("/data is not mounted NODEV", (vfs.f_flag & OsConstants.ST_NODEV) != 0);
     }
 
     public void testAllBlockDevicesAreSecure() throws Exception {
@@ -1020,48 +1042,4 @@
         return !f.getAbsolutePath().equals(f.getCanonicalPath());
     }
 
-    private static class ParsedMounts {
-        private HashMap<String, Boolean> mFileReadOnlyMap = new HashMap<String, Boolean>();
-
-        private ParsedMounts(String filename) throws IOException {
-            BufferedReader br = new BufferedReader(new FileReader(filename));
-            try {
-                String line;
-                while ((line = br.readLine()) != null) {
-                    String[] fields = line.split(" ");
-                    String mountPoint = fields[1];
-                    String all_options = fields[3];
-                    String[] options = all_options.split(",");
-                    boolean foundRo = false;
-                    for (String option : options) {
-                        if ("ro".equals(option)) {
-                            foundRo = true;
-                            break;
-                        }
-                    }
-                    mFileReadOnlyMap.put(mountPoint, foundRo);
-                }
-           } finally {
-               br.close();
-           }
-        }
-
-        private boolean isMountReadOnly(String s) {
-            return mFileReadOnlyMap.get(s).booleanValue();
-        }
-
-        private String findMountPointContaining(File f) throws IOException {
-            while (f != null) {
-                f = f.getCanonicalFile();
-                String path = f.getPath();
-                if (mFileReadOnlyMap.containsKey(path)) {
-                    return path;
-                }
-                f = f.getParentFile();
-            }
-            // This should NEVER be reached, as we'll eventually hit the
-            // root directory.
-            throw new AssertionError("Unable to find mount point");
-        }
-    }
 }
diff --git a/tests/tests/print/Android.mk b/tests/tests/print/Android.mk
index 516f6a0..2ece2cf 100644
--- a/tests/tests/print/Android.mk
+++ b/tests/tests/print/Android.mk
@@ -18,15 +18,11 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    src/android/print/cts/IPrivilegedOperations.aidl
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsPrintTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator
-
-# This test runner sets up/cleans up the device before/after running the tests.
-LOCAL_CTS_TEST_RUNNER := com.android.cts.tradefed.testtype.PrintTestRunner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator ctsdeviceutil
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index c73bb64..31dfb9f 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.cts.util.SystemUtil;
 import android.graphics.pdf.PdfDocument;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -73,12 +74,12 @@
 
     private static final long OPERATION_TIMEOUT = 100000000;
 
-    private static final String ARG_PRIVILEGED_OPS = "ARG_PRIVILEGED_OPS";
-
     private static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
 
     protected static final String PRINT_JOB_NAME = "Test";
 
+    private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
+
     private PrintDocumentActivity mActivity;
 
     private Locale mOldLocale;
@@ -94,6 +95,7 @@
     public void setUp() throws Exception {
         // Make sure we start with a clean slate.
         clearPrintSpoolerData();
+        enablePrintServices();
 
         // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
         // Dexmaker is used by mockito.
@@ -139,6 +141,7 @@
             resources.updateConfiguration(newConfiguration, displayMetrics);
         }
 
+        disablePrintServices();
         // Make sure the spooler is cleaned.
         clearPrintSpoolerData();
     }
@@ -272,6 +275,19 @@
         }
     }
 
+    protected void changeDuplex(String duplex) throws UiObjectNotFoundException {
+        try {
+            UiObject duplexSpinner = new UiObject(new UiSelector().resourceId(
+                    "com.android.printspooler:id/duplex_spinner"));
+            duplexSpinner.click();
+            UiObject duplexOption = new UiObject(new UiSelector().text(duplex));
+            duplexOption.click();
+        } catch (UiObjectNotFoundException e) {
+            dumpWindowHierarchy();
+            throw new UiObjectNotFoundException(e);
+        }
+    }
+
     protected void clickPrintButton() throws UiObjectNotFoundException {
         try {
             UiObject printButton = new UiObject(new UiSelector().resourceId(
@@ -306,9 +322,24 @@
     }
 
     protected void clearPrintSpoolerData() throws Exception {
-        IPrivilegedOperations privilegedOps = IPrivilegedOperations.Stub.asInterface(
-                getParams().getBinder(ARG_PRIVILEGED_OPS));
-        privilegedOps.clearApplicationUserData(PRINT_SPOOLER_PACKAGE_NAME);
+        assertTrue("failed to clear print spooler data",
+                SystemUtil.runShellCommand(getInstrumentation(),
+                        String.format("pm clear %s", PRINT_SPOOLER_PACKAGE_NAME))
+                            .contains(PM_CLEAR_SUCCESS_OUTPUT));
+    }
+
+    private void enablePrintServices() throws Exception {
+        String pkgName = getInstrumentation().getContext().getPackageName();
+        String enabledServicesValue = String.format("%s/%s:%s/%s",
+                pkgName, FirstPrintService.class.getCanonicalName(),
+                pkgName, SecondPrintService.class.getCanonicalName());
+        SystemUtil.runShellCommand(getInstrumentation(),
+                "settings put secure enabled_print_services " + enabledServicesValue);
+    }
+
+    private void disablePrintServices() throws Exception {
+        SystemUtil.runShellCommand(getInstrumentation(),
+                "settings put secure enabled_print_services \"\"");
     }
 
     protected void verifyLayoutCall(InOrder inOrder, PrintDocumentAdapter mock,
diff --git a/tests/tests/print/src/android/print/cts/IPrivilegedOperations.aidl b/tests/tests/print/src/android/print/cts/IPrivilegedOperations.aidl
deleted file mode 100644
index 93c8c3e..0000000
--- a/tests/tests/print/src/android/print/cts/IPrivilegedOperations.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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 android.print.cts;
-
-interface IPrivilegedOperations {
-    boolean clearApplicationUserData(String packageName);
-}
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index 538472e..c17583f 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -353,6 +353,12 @@
         // Wait for layout.
         waitForLayoutAdapterCallbackCount(5);
 
+        // Change the duplex.
+        changeDuplex("Short edge");
+
+        // Wait for layout.
+        waitForLayoutAdapterCallbackCount(6);
+
         // Click the print button.
         clickPrintButton();
 
@@ -394,6 +400,7 @@
                 .setResolution(new Resolution("300x300", "300x300", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_LONG_EDGE)
                 .build();
         verifyLayoutCall(inOrder, adapter, secondOldAttributes, secondNewAttributes, true);
 
@@ -406,6 +413,7 @@
                 .setResolution(new Resolution("300x300", "300x300", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_LONG_EDGE)
                 .build();
         verifyLayoutCall(inOrder, adapter, thirdOldAttributes, thirdNewAttributes, true);
 
@@ -418,6 +426,7 @@
                 .setResolution(new Resolution("300x300", "300x300", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_LONG_EDGE)
                 .build();
         verifyLayoutCall(inOrder, adapter, fourthOldAttributes, fourthNewAttributes, true);
 
@@ -430,11 +439,25 @@
                 .setResolution(new Resolution("300x300", "300x300", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_LONG_EDGE)
                 .build();
         verifyLayoutCall(inOrder, adapter, fifthOldAttributes, fifthNewAttributes, true);
 
+        // We changed the duplex which triggers a layout. Since we passed
+        // false to the layout callback meaning that the content didn't change,
+        // there shouldn't be a next call to write.
+        PrintAttributes sixthOldAttributes = fifthNewAttributes;
+        PrintAttributes sixthNewAttributes = new PrintAttributes.Builder()
+                .setMediaSize(MediaSize.ISO_A4.asLandscape())
+                .setResolution(new Resolution("300x300", "300x300", 300, 300))
+                .setMinMargins(Margins.NO_MARGINS)
+                .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_SHORT_EDGE)
+                .build();
+        verifyLayoutCall(inOrder, adapter, sixthOldAttributes, sixthNewAttributes, true);
+
         // When print is pressed we ask for a layout which is *not* for preview.
-        verifyLayoutCall(inOrder, adapter, fifthNewAttributes, fifthNewAttributes, false);
+        verifyLayoutCall(inOrder, adapter, sixthNewAttributes, sixthNewAttributes, false);
 
         // When print is pressed we ask for all selected pages but we got
         // them when asking for the ones for a preview, and the adapter does
@@ -1573,8 +1596,13 @@
                         .addResolution(new Resolution("200x200", "200x200", 200, 200), true)
                         .addResolution(new Resolution("300x300", "300x300", 300, 300), false)
                         .setColorModes(PrintAttributes.COLOR_MODE_COLOR
-                                | PrintAttributes.COLOR_MODE_MONOCHROME,
-                                PrintAttributes.COLOR_MODE_MONOCHROME)
+                                        | PrintAttributes.COLOR_MODE_MONOCHROME,
+                                PrintAttributes.COLOR_MODE_MONOCHROME
+                        )
+                        .setDuplexModes(PrintAttributes.DUPLEX_MODE_LONG_EDGE
+                                        | PrintAttributes.DUPLEX_MODE_SHORT_EDGE,
+                                PrintAttributes.DUPLEX_MODE_LONG_EDGE
+                        )
                         .build();
                     PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
                             "Second printer", PrinterInfo.STATUS_IDLE)
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index abda46c..855c4ce 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -18,6 +18,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.cts.provider">
 
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
+
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
     <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
     <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_AggregationSuggestionsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_AggregationSuggestionsTest.java
new file mode 100644
index 0000000..1aa2b64
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_AggregationSuggestionsTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Contacts.AggregationSuggestions;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
+import android.provider.cts.contacts.DatabaseAsserts;
+import android.test.AndroidTestCase;
+
+/**
+ * CTS tests for {@link android.provider.ContactsContract.Contacts.AggregationSuggestions} APIs.
+ */
+public class ContactsContract_AggregationSuggestionsTest extends AndroidTestCase {
+    private static final String[] TEST_PROJECTION
+            = new String[] {Contacts.DISPLAY_NAME, Contacts._ID};
+
+    private ContentResolver mResolver;
+    private ContactsContract_TestDataBuilder mBuilder;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResolver = getContext().getContentResolver();
+        ContentProviderClient provider =
+                mResolver.acquireContentProviderClient(ContactsContract.AUTHORITY);
+        mBuilder = new ContactsContract_TestDataBuilder(provider);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mBuilder.cleanup();
+    }
+
+    // Copy of CP2's ContactAggregatorTest#testAggregationSuggestionsByName unit test.
+    public void testAggregationSuggestionsByNameReversed() throws Exception {
+        long [] contactIds = setupThreeContacts();
+
+        // Setup: create query with first and last name reversed.
+        Uri uri = AggregationSuggestions.builder()
+                .addNameParameter("last1 first1")
+                .build();
+
+        // Execute
+        Cursor cursor = mResolver.query(uri, TEST_PROJECTION, null, null, null);
+
+        // Verify: correct contact is returned.
+        assertEquals(1, cursor.getCount());
+        cursor.moveToFirst();
+        ContentValues values = new ContentValues();
+        values.put(Contacts._ID, contactIds[0]);
+        values.put(Contacts.DISPLAY_NAME, "first1 last1");
+        DatabaseAsserts.assertCursorValuesMatchExactly(cursor, values);
+        cursor.close();
+    }
+
+
+    public void testAggregationSuggestionsByName() throws Exception {
+        long [] contactIds = setupThreeContacts();
+
+        // Setup: create query with first and last name in same order as display name.
+        Uri uri = AggregationSuggestions.builder()
+                .addNameParameter("first1 last1")
+                .build();
+
+        // Execute
+        Cursor cursor = mResolver.query(uri, TEST_PROJECTION, null, null, null);
+
+        // Verify: correct contact is returned.
+        assertEquals(1, cursor.getCount());
+        cursor.moveToFirst();
+        ContentValues values = new ContentValues();
+        values.put(Contacts._ID, contactIds[0]);
+        values.put(Contacts.DISPLAY_NAME, "first1 last1");
+        DatabaseAsserts.assertCursorValuesMatchExactly(cursor, values);
+        cursor.close();
+    }
+
+    public void testAggregationSuggestionsByName_noMatch() throws Exception {
+        setupThreeContacts();
+
+        // Setup: query with name that is completely different than all the contacts.
+        Uri uri = AggregationSuggestions.builder()
+                .addNameParameter("unmatched name")
+                .build();
+
+        // Execute
+        Cursor cursor = mResolver.query(
+                uri, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null);
+
+        // Verify: no matches.
+        assertEquals(0, cursor.getCount());
+    }
+
+    public void testAggregationSuggestionsByName_matchSecondNameParameter() throws Exception {
+        long [] contactIds = setupThreeContacts();
+
+        // Setup: query with two names. The first name is completely unlike all the contacts.
+        Uri uri = AggregationSuggestions.builder()
+                .addNameParameter("unmatched name")
+                .addNameParameter("first2 last2")
+                .build();
+
+        // Execute
+        Cursor cursor = mResolver.query(uri, TEST_PROJECTION, null, null, null);
+
+        // Verify: the second name parameter matches a contact.
+        assertEquals(1, cursor.getCount());
+        ContentValues values = new ContentValues();
+        values.put(Contacts._ID, contactIds[1]);
+        values.put(Contacts.DISPLAY_NAME, "first2 last2");
+        DatabaseAsserts.assertCursorValuesMatchExactly(cursor, values);
+        cursor.close();
+    }
+
+    public void testAggregationSuggestionsByName_matchFirstNameParameter() throws Exception {
+        long [] contactIds = setupThreeContacts();
+
+        // Setup: query with two names. The second name is completely unlike all the contacts.
+        Uri uri = AggregationSuggestions.builder()
+                .addNameParameter("first2 last2")
+                .addNameParameter("unmatched name")
+                .build();
+
+        // Execute
+        Cursor cursor = mResolver.query(uri, TEST_PROJECTION, null, null, null);
+
+        // Verify: the first name parameter matches a contact.
+        assertEquals(1, cursor.getCount());
+        ContentValues values = new ContentValues();
+        values.put(Contacts._ID, contactIds[1]);
+        values.put(Contacts.DISPLAY_NAME, "first2 last2");
+        DatabaseAsserts.assertCursorValuesMatchExactly(cursor, values);
+        cursor.close();
+    }
+
+    private long[] setupThreeContacts() throws Exception {
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "first1")
+                .with(StructuredName.FAMILY_NAME, "last1")
+                .insert();
+        rawContact1.load();
+
+        TestRawContact rawContact2 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        rawContact2.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "first2")
+                .with(StructuredName.FAMILY_NAME, "last2")
+                .insert();
+        rawContact2.load();
+
+        TestRawContact rawContact3 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        rawContact3.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "completely")
+                .with(StructuredName.FAMILY_NAME, "different")
+                .insert();
+        rawContact3.load();
+
+        return new long[] {rawContact1.getContactId(),
+                rawContact2.getContactId(), rawContact3.getContactId()};
+    }
+}
+
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_AuthorizationTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_AuthorizationTest.java
new file mode 100644
index 0000000..3fea65d
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_AuthorizationTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Contacts.AggregationSuggestions;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
+import android.provider.cts.contacts.DatabaseAsserts;
+import android.test.AndroidTestCase;
+
+/**
+ * CTS tests for {@link android.provider.ContactsContract.Authorization} APIs.
+ *
+ * It isn't possible to fully test the Authorization API. Suppose this apk doesn't have
+ * the necessary permissions. In this case, we can't call the authorization API in the first place.
+ * On the other hand, suppose this apk does have the necessary permissions. In this case, we can't
+ * check that the Authorization API added any permissions to the URI since we could already use the
+ * URI anyway.
+ */
+public class ContactsContract_AuthorizationTest extends AndroidTestCase {
+    private static final String[] TEST_PROJECTION = new String[] {Contacts.DISPLAY_NAME};
+
+    private ContentResolver mResolver;
+    private ContactsContract_TestDataBuilder mBuilder;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResolver = getContext().getContentResolver();
+        ContentProviderClient provider =
+                mResolver.acquireContentProviderClient(ContactsContract.AUTHORITY);
+        mBuilder = new ContactsContract_TestDataBuilder(provider);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mBuilder.cleanup();
+    }
+
+    public void testAuthorization_contact1() throws Exception {
+        // Setup
+        Uri [] contactUris = setupTwoContacts();
+
+        // Execute
+        Uri preAuthorizedUri = getPreAuthorizedUri(contactUris[0]);
+
+        // Verify: the pre-authorized URI is different than the original URI, but still works.
+        assertNotSame(preAuthorizedUri, contactUris[0]);
+        Cursor cursor = mResolver.query(preAuthorizedUri, TEST_PROJECTION, null, null, null);
+        assertEquals(1, cursor.getCount());
+        ContentValues values = new ContentValues();
+        values.put(Contacts.DISPLAY_NAME, "first1 last1");
+        DatabaseAsserts.assertCursorValuesMatchExactly(cursor, values);
+        cursor.close();
+    }
+
+    public void testAuthorization_contact2() throws Exception {
+        // Setup
+        Uri [] contactUris = setupTwoContacts();
+
+        // Execute
+        Uri preAuthorizedUri = getPreAuthorizedUri(contactUris[1]);
+
+        // Verify: the pre-authorized URI is different than the original URI, but still works.
+        assertNotSame(preAuthorizedUri, contactUris[1]);
+        Cursor cursor = mResolver.query(preAuthorizedUri, TEST_PROJECTION, null, null, null);
+        assertEquals(1, cursor.getCount());
+        ContentValues values = new ContentValues();
+        values.put(Contacts.DISPLAY_NAME, "first2 last2");
+        DatabaseAsserts.assertCursorValuesMatchExactly(cursor, values);
+        cursor.close();
+    }
+
+    public void testAuthorization_profile() throws Exception {
+        try {
+            getPreAuthorizedUri(ContactsContract.Profile.CONTENT_URI);
+            fail("getPreAuthorizedUri(ContactsContract.Profile.CONTENT_URI) did not throw"
+                    + "SecurityException as expected");
+        } catch (SecurityException se) {
+            // Verify: can't authorize a profile URI without the READ_PROFILE permission.
+        }
+    }
+
+    private Uri getPreAuthorizedUri(Uri uri) {
+        final Bundle uriBundle = new Bundle();
+        uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri);
+        final Bundle authResponse = mResolver.call(
+                ContactsContract.AUTHORITY_URI,
+                ContactsContract.Authorization.AUTHORIZATION_METHOD,
+                null,
+                uriBundle);
+        return authResponse.getParcelable(ContactsContract.Authorization.KEY_AUTHORIZED_URI);
+    }
+
+    private Uri[] setupTwoContacts() throws Exception {
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "first1")
+                .with(StructuredName.FAMILY_NAME, "last1")
+                .insert();
+        rawContact1.load();
+        TestContact testContact1 = rawContact1.getContact().load();
+        Uri contactUri1 = testContact1.getUri();
+
+        TestRawContact rawContact2 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        rawContact2.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "first2")
+                .with(StructuredName.FAMILY_NAME, "last2")
+                .insert();
+        rawContact2.load();
+        TestContact testContact2 = rawContact2.getContact().load();
+        Uri contactUri2 = testContact2.getUri();
+
+        return new Uri[] {contactUri1, contactUri2};
+    }
+
+}
+
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
index 006f4df..d16cb9d 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
@@ -101,6 +101,12 @@
         assertEquals(ContentUris.withAppendedId(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI,
                 lookupKey), contactId), lookupUri);
 
+        Uri nullLookupUri = Contacts.getLookupUri(contactId, null);
+        assertNull(nullLookupUri);
+
+        Uri emptyLookupUri = Contacts.getLookupUri(contactId, "");
+        assertNull(emptyLookupUri);
+
         Uri lookupUri2 = Contacts.getLookupUri(mResolver, contactUri);
         assertEquals(lookupUri, lookupUri2);
 
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_IsSuperPrimaryName.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_IsSuperPrimaryName.java
new file mode 100644
index 0000000..4ff6a88
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_IsSuperPrimaryName.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts;
+
+import junit.framework.Assert;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestData;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
+import android.test.AndroidTestCase;
+
+/**
+ * CTS tests for the affect that {@link ContactsContract.Data#IS_SUPER_PRIMARY} has on names inside
+ * aggregated contacts. Additionally, this needs to test the affect that aggregating contacts
+ * together has on IS_SUPER_PRIMARY values in order to enforce the desired IS_SUPER_PRIMARY
+ * behavior.
+ */
+public class ContactsContract_IsSuperPrimaryName extends AndroidTestCase {
+
+    private ContentResolver mResolver;
+    private ContactsContract_TestDataBuilder mBuilder;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResolver = getContext().getContentResolver();
+        ContentProviderClient provider =
+                mResolver.acquireContentProviderClient(ContactsContract.AUTHORITY);
+        mBuilder = new ContactsContract_TestDataBuilder(provider);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mBuilder.cleanup();
+        super.tearDown();
+    }
+
+    public void testIsSuperPrimary_name1SuperPrimary() throws Exception {
+        testInner_displayNameFromIsSuperPrimary(/* isFirstNamePrimary = */ true, "name1", "name2");
+    }
+
+    public void testIsSuperPrimary_name2SuperPrimary() throws Exception {
+        testInner_displayNameFromIsSuperPrimary(/* isFirstNamePrimary = */ false, "name2", "name1");
+    }
+
+    private void testInner_displayNameFromIsSuperPrimary(boolean isFirstNamePrimary,
+            String expectedDisplayName, String otherDisplayName) throws Exception {
+
+        // Setup: two raw contacts. One with a super primary name. One without.
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name1 = rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "name1")
+                .with(StructuredName.IS_SUPER_PRIMARY, isFirstNamePrimary ? 1 : 0)
+                .insert();
+        rawContact1.load();
+        name1.load();
+
+        TestRawContact rawContact2 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name2 = rawContact2.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "name2")
+                .with(StructuredName.IS_SUPER_PRIMARY, !isFirstNamePrimary ? 1 : 0)
+                .insert();
+        rawContact2.load();
+        name2.load();
+
+        // Execute: aggregate the two raw contacts together
+        setAggregationException(rawContact1.getId(), rawContact2.getId());
+
+        // Sanity check: two contacts are aggregated
+        rawContact1.load();
+        rawContact2.load();
+        Assert.assertEquals(rawContact1.getContactId(), rawContact2.getContactId());
+
+        // Verify: the IS_SUPER_PRIMARY values are maintained after the merge
+        name1.assertColumn(StructuredName.IS_SUPER_PRIMARY, isFirstNamePrimary ? 1 : 0);
+        name2.assertColumn(StructuredName.IS_SUPER_PRIMARY, !isFirstNamePrimary ? 1 : 0);
+
+        // Verify: the display name is taken from the name with is_super_primary
+        TestContact contact = rawContact2.getContact().load();
+        contact.assertColumn(Contacts.DISPLAY_NAME, expectedDisplayName);
+
+        //
+        // Now test what happens when you change IS_SUPER_PRIMARY on an existing contact
+        //
+
+        // Execute: make the non primary name IS_SUPER_PRIMARY
+        TestData nonPrimaryName = isFirstNamePrimary ? name1 : name2;
+        ContentValues values = new ContentValues();
+        values.put(StructuredName.IS_SUPER_PRIMARY, 1);
+        mResolver.update(nonPrimaryName.getContentUri(), values, null, null);
+
+        // Verify: the IS_SUPER_PRIMARY values swap
+        name1.load();
+        name2.load();
+        name1.assertColumn(StructuredName.IS_SUPER_PRIMARY, isFirstNamePrimary ? 0 : 1);
+        name2.assertColumn(StructuredName.IS_SUPER_PRIMARY, !isFirstNamePrimary ? 0 : 1);
+
+        // Verify: the display name is taken from the name with is_super_primary
+        contact.load();
+        contact.assertColumn(Contacts.DISPLAY_NAME, otherDisplayName);
+    }
+
+    public void testIsSuperPrimaryName_mergeBothSuperPrimary() throws Exception {
+        // Setup: two raw contacts. Both names are super primary.
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name1 = rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "name1")
+                .with(StructuredName.IS_SUPER_PRIMARY, 1)
+                .insert();
+        rawContact1.load();
+        name1.load();
+
+        TestRawContact rawContact2 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name2 = rawContact2.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "name2")
+                .with(StructuredName.IS_SUPER_PRIMARY, 1)
+                .insert();
+        rawContact2.load();
+        name2.load();
+
+        // Execute: aggregate the two contacts together
+        setAggregationException(rawContact1.getId(), rawContact2.getId());
+
+        // Sanity check: two contacts are aggregated
+        rawContact1.load();
+        rawContact2.load();
+        Assert.assertEquals(rawContact1.getContactId(), rawContact2.getContactId());
+
+        // Verify: both names are no longer super primary.
+        name1.load();
+        name2.load();
+        name1.assertColumn(StructuredName.IS_SUPER_PRIMARY, 0);
+        name2.assertColumn(StructuredName.IS_SUPER_PRIMARY, 0);
+    }
+
+    private void setAggregationException(long rawContactId1, long rawContactId2) {
+        ContentValues values = new ContentValues();
+        values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
+        values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
+        values.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
+        mResolver.update(AggregationExceptions.CONTENT_URI, values, null, null);
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_ProviderStatus.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_ProviderStatus.java
new file mode 100644
index 0000000..54bea8e
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_ProviderStatus.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.ProviderStatus;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
+import android.provider.cts.contacts.DatabaseAsserts;
+import android.test.AndroidTestCase;
+
+/**
+ * CTS tests for {@link android.provider.ContactsContract.ProviderStatus}.
+ *
+ * Unfortunately, we can't check that the value of ProviderStatus equals
+ * {@link ProviderStatus#STATUS_NO_ACCOUNTS_NO_CONTACTS} initially. Some carriers pre-install
+ * accounts. As a result, the value STATUS_NO_ACCOUNTS_NO_CONTACTS will never be achieved.
+ */
+public class ContactsContract_ProviderStatus extends AndroidTestCase {
+    private ContentResolver mResolver;
+    private ContactsContract_TestDataBuilder mBuilder;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResolver = getContext().getContentResolver();
+        ContentProviderClient provider =
+                mResolver.acquireContentProviderClient(ContactsContract.AUTHORITY);
+        mBuilder = new ContactsContract_TestDataBuilder(provider);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mBuilder.cleanup();
+    }
+
+    public void testProviderStatus_addedContacts() throws Exception {
+        // Setup: add a contact to CP2.
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "first1")
+                .with(StructuredName.FAMILY_NAME, "last1")
+                .insert();
+
+        // Execute: fetch CP2 status
+        Cursor cursor = mResolver.query(ProviderStatus.CONTENT_URI, null, null, null, null);
+
+        // Verify: CP2 status is normal instead of STATUS_NO_ACCOUNTS_NO_CONTACTS.
+        try {
+            assertEquals(1, cursor.getCount());
+            cursor.moveToFirst();
+            ContentValues values = new ContentValues();
+            values.put(ProviderStatus.STATUS, ProviderStatus.STATUS_NORMAL);
+            DatabaseAsserts.assertCursorValuesMatchExactly(cursor, values);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+}
+
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_StructuredPhoneticName.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_StructuredPhoneticName.java
new file mode 100644
index 0000000..4efd9a7
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_StructuredPhoneticName.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts;
+
+import junit.framework.Assert;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.DisplayNameSources;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestData;
+import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
+import android.provider.cts.contacts.ContactUtil;
+import android.test.AndroidTestCase;
+
+/**
+ * CTS tests for {@link DisplayNameSources#STRUCTURED_PHONETIC_NAME}.
+ */
+public class ContactsContract_StructuredPhoneticName extends AndroidTestCase {
+    private ContentResolver mResolver;
+    private ContactsContract_TestDataBuilder mBuilder;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResolver = getContext().getContentResolver();
+        ContentProviderClient provider =
+                mResolver.acquireContentProviderClient(ContactsContract.AUTHORITY);
+        mBuilder = new ContactsContract_TestDataBuilder(provider);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mBuilder.cleanup();
+        super.tearDown();
+    }
+
+    public void testPhoneticStructuredName() throws Exception {
+        // Setup: contact with only phonetic name
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name1 = rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.PHONETIC_FAMILY_NAME, "phonetic name")
+                .insert();
+        rawContact1.load();
+        name1.load();
+
+        // Verify: DISPLAY_NAME_SOURCE notices that the StructuredName only has phonetic components
+        TestContact contact = rawContact1.getContact().load();
+        contact.assertColumn(Contacts.DISPLAY_NAME_SOURCE,
+                DisplayNameSources.STRUCTURED_PHONETIC_NAME);
+    }
+
+    public void testPhoneticStructuredName_phoneticPriority1() throws Exception {
+        // Setup: one raw contact has a complex phonetic name and the other a simple given name
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name1 = rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "name")
+                .insert();
+        rawContact1.load();
+        name1.load();
+
+        TestRawContact rawContact2 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name2 = rawContact2.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.PHONETIC_FAMILY_NAME, "name phonetic")
+                .insert();
+        rawContact2.load();
+        name2.load();
+
+        // Execute: aggregate the two raw contacts together
+        ContactUtil.setAggregationException(mResolver, AggregationExceptions.TYPE_KEEP_TOGETHER,
+                rawContact1.getId(), rawContact2.getId());
+
+        // Sanity check: two contacts are aggregated
+        rawContact1.load();
+        rawContact2.load();
+        Assert.assertEquals(rawContact1.getContactId(), rawContact2.getContactId());
+
+        // Verify: the display name is taken from the name with more than phonetic components
+        TestContact contact = rawContact2.getContact().load();
+        contact.assertColumn(Contacts.DISPLAY_NAME, "name");
+    }
+
+    // Same as testPhoneticStructuredName_phoneticPriority1, but with setup order reversed
+    public void testPhoneticStructuredName_phoneticPriority2() throws Exception {
+        // Setup: one raw contact has a complex phonetic name and the other a simple given name
+        TestRawContact rawContact2 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name2 = rawContact2.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.PHONETIC_FAMILY_NAME, "name phonetic")
+                .insert();
+        rawContact2.load();
+        name2.load();
+
+        TestRawContact rawContact1 = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_account")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .insert();
+        TestData name1 = rawContact1.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+                .with(StructuredName.GIVEN_NAME, "name")
+                .insert();
+        rawContact1.load();
+        name1.load();
+
+        // Execute: aggregate the two raw contacts together
+        ContactUtil.setAggregationException(mResolver, AggregationExceptions.TYPE_KEEP_TOGETHER,
+                rawContact1.getId(), rawContact2.getId());
+
+        // Sanity check: two contacts are aggregated
+        rawContact1.load();
+        rawContact2.load();
+        Assert.assertEquals(rawContact1.getContactId(), rawContact2.getContactId());
+
+        // Verify: the display name is taken from the name with more than phonetic components
+        TestContact contact = rawContact2.getContact().load();
+        contact.assertColumn(Contacts.DISPLAY_NAME, "name");
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsTest.java
index 9a3fc19..9febaa2 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsTest.java
@@ -416,7 +416,7 @@
                 Calls.CACHED_NUMBER_LABEL, Calls.CACHED_FORMATTED_NUMBER,
                 Calls.CACHED_MATCHED_NUMBER, Calls.CACHED_NORMALIZED_NUMBER,
                 Calls.CACHED_LOOKUP_URI, Calls.CACHED_PHOTO_ID, Calls.COUNTRY_ISO,
-                Calls.GEOCODED_LOCATION};
+                Calls.GEOCODED_LOCATION, Calls.CACHED_PHOTO_URI};
         final int ID_INDEX = 0;
         final int NUMBER_INDEX = 1;
         final int DATE_INDEX = 2;
@@ -433,6 +433,7 @@
         final int CACHED_PHOTO_ID_INDEX = 13;
         final int COUNTRY_ISO_INDEX = 14;
         final int GEOCODED_LOCATION_INDEX = 15;
+        final int CACHED_PHOTO_URI_INDEX = 16;
 
         String insertCallsNumber = "0123456789";
         int insertCallsDuration = 120;
@@ -448,6 +449,7 @@
         String updateCachedNormalizedNumber = "+1987654321";
         String updateCachedLookupUri = "cached_lookup_uri_update";
         long updateCachedPhotoId = 100;
+        String updateCachedPhotoUri = "content://com.android.contacts/display_photo/1";
         String updateCountryIso = "hk";
         String updateGeocodedLocation = "Hong Kong";
 
@@ -497,6 +499,7 @@
             value.put(Calls.CACHED_MATCHED_NUMBER, updateCachedMatchedNumber);
             value.put(Calls.CACHED_NORMALIZED_NUMBER, updateCachedNormalizedNumber);
             value.put(Calls.CACHED_PHOTO_ID, updateCachedPhotoId);
+            value.put(Calls.CACHED_PHOTO_URI, updateCachedPhotoUri);
             value.put(Calls.COUNTRY_ISO, updateCountryIso);
             value.put(Calls.GEOCODED_LOCATION, updateGeocodedLocation);
             value.put(Calls.CACHED_LOOKUP_URI, updateCachedLookupUri);
@@ -519,6 +522,7 @@
             assertEquals(updateCachedNormalizedNumber,
                     cursor.getString(CACHED_NORMALIZED_NUMBER_INDEX));
             assertEquals(updateCachedPhotoId, cursor.getLong(CACHED_PHOTO_ID_INDEX));
+            assertEquals(updateCachedPhotoUri, cursor.getString(CACHED_PHOTO_URI_INDEX));
             assertEquals(updateCountryIso, cursor.getString(COUNTRY_ISO_INDEX));
             assertEquals(updateGeocodedLocation, cursor.getString(GEOCODED_LOCATION_INDEX));
             assertEquals(updateCachedLookupUri, cursor.getString(CACHED_LOOKUP_URI_INDEX));
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsTest.java b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
index c732305..5cf5106 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
@@ -16,7 +16,6 @@
 
 package android.provider.cts;
 
-
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -35,14 +34,11 @@
         final String[] SYSTEM_PROJECTION = new String[] {
                 Settings.System._ID, Settings.System.NAME, Settings.System.VALUE
         };
-        final int ID_INDEX = 0;
         final int NAME_INDEX = 1;
         final int VALUE_INDEX = 2;
 
-        String insertName = "name_insert";
+        String name = "name";
         String insertValue = "value_insert";
-
-        String updateName = "name_update";
         String updateValue = "value_update";
 
         // get provider
@@ -54,119 +50,50 @@
         try {
             // Test: insert
             ContentValues value = new ContentValues();
-            value.put(Settings.System.NAME, insertName);
+            value.put(Settings.System.NAME, name);
             value.put(Settings.System.VALUE, insertValue);
 
             provider.insert(Settings.System.CONTENT_URI, value);
             cursor = provider.query(Settings.System.CONTENT_URI, SYSTEM_PROJECTION,
-                    Settings.System.NAME + "=\"" + insertName + "\"", null, null, null);
+                    Settings.System.NAME + "=\"" + name + "\"", null, null, null);
             assertNotNull(cursor);
             assertEquals(1, cursor.getCount());
             assertTrue(cursor.moveToFirst());
-            assertEquals(insertName, cursor.getString(NAME_INDEX));
+            assertEquals(name, cursor.getString(NAME_INDEX));
             assertEquals(insertValue, cursor.getString(VALUE_INDEX));
-            int Id = cursor.getInt(ID_INDEX);
             cursor.close();
+            cursor = null;
 
             // Test: update
             value.clear();
-            value.put(Settings.System.NAME, updateName);
+            value.put(Settings.System.NAME, name);
             value.put(Settings.System.VALUE, updateValue);
 
             provider.update(Settings.System.CONTENT_URI, value,
-                    Settings.System.NAME + "=\"" + insertName + "\"", null);
+                    Settings.System.NAME + "=\"" + name + "\"", null);
             cursor = provider.query(Settings.System.CONTENT_URI, SYSTEM_PROJECTION,
-                    Settings.System._ID + " = " + Id, null, null, null);
+                    Settings.System.NAME + "=\"" + name + "\"", null, null, null);
             assertNotNull(cursor);
             assertEquals(1, cursor.getCount());
             assertTrue(cursor.moveToFirst());
-            assertEquals(updateName, cursor.getString(NAME_INDEX));
+            assertEquals(name, cursor.getString(NAME_INDEX));
             assertEquals(updateValue, cursor.getString(VALUE_INDEX));
             cursor.close();
+            cursor = null;
 
             // Test: delete
             provider.delete(Settings.System.CONTENT_URI,
-                    Settings.System.NAME + "=\"" + updateName + "\"", null);
+                    Settings.System.NAME + "=\"" + name + "\"", null);
             cursor = provider.query(Settings.System.CONTENT_URI, SYSTEM_PROJECTION,
-                    Settings.System._ID + " = " + Id, null, null, null);
+                    Settings.System.NAME + "=\"" + name + "\"", null, null, null);
             assertNotNull(cursor);
             assertEquals(0, cursor.getCount());
-        } finally {
-            // TODO should clean up more better
-            if (cursor != null)
-                cursor.close();
-        }
-    }
-
-    public void testBluetoothDevicesTable() throws RemoteException {
-        final String[] BLUETOOTH_DEVICES_PROJECTION = new String[] {
-                "name", "addr", "channel", "type"
-        };
-        final int ID_INDEX = 0;
-        final int ADDR_INDEX = 1;
-        final int CHANNEL_INDEX = 2;
-        final int TYPE_INDEX = 3;
-
-        String insertName = "name_insert";
-        String insertAddr = "addr_insert";
-
-        String updateName = "name_update";
-        String updateAddr = "addr_update";
-
-        // get provider
-        Uri uri = Uri.parse("content://settings/bluetooth_devices");
-        ContentResolver cr = mContext.getContentResolver();
-        ContentProviderClient provider = cr.acquireContentProviderClient(uri);
-        Cursor cursor = null;
-
-        try {
-            // Test: insert
-            ContentValues value = new ContentValues();
-            value.put("name", insertName);
-            value.put("addr", insertAddr);
-            value.put("channel", 1);
-            value.put("type", 2);
-
-            provider.insert(uri, value);
-            cursor = provider.query(uri, BLUETOOTH_DEVICES_PROJECTION,
-                    "name=\"" + insertName + "\"", null, null, null);
-            assertNotNull(cursor);
-            assertEquals(1, cursor.getCount());
-            assertTrue(cursor.moveToFirst());
-            assertEquals(insertAddr, cursor.getString(ADDR_INDEX));
-            assertEquals(1, cursor.getInt(CHANNEL_INDEX));
-            assertEquals(2, cursor.getInt(TYPE_INDEX));
-            int Id = cursor.getInt(ID_INDEX);
             cursor.close();
-
-            // Test: update
-            value.clear();
-            value.put("name", updateName);
-            value.put("addr", updateAddr);
-            value.put("channel", 3);
-            value.put("type", 4);
-
-            provider.update(uri, value, "name=\"" + insertName + "\"", null);
-            cursor = provider.query(uri, BLUETOOTH_DEVICES_PROJECTION,
-                    "name=\"" + updateName + "\"", null, null, null);
-            assertNotNull(cursor);
-            assertEquals(1, cursor.getCount());
-            assertTrue(cursor.moveToFirst());
-            assertEquals(updateAddr, cursor.getString(ADDR_INDEX));
-            assertEquals(3, cursor.getInt(CHANNEL_INDEX));
-            assertEquals(4, cursor.getInt(TYPE_INDEX));
-            cursor.close();
-
-            // Test: delete
-            provider.delete(uri, "name=\"" + updateName + "\"", null);
-            cursor = provider.query(uri, BLUETOOTH_DEVICES_PROJECTION, "_id = " + Id,
-                    null, null, null);
-            assertNotNull(cursor);
-            assertEquals(0, cursor.getCount());
+            cursor = null;
         } finally {
-            // TODO should clean up more better
-            if (cursor != null)
+            if (cursor != null) {
                 cursor.close();
+            }
         }
     }
 
@@ -211,22 +138,24 @@
             fail("SettingsProvider didn't throw IllegalArgumentException for insert name "
                     + name + " at URI " + uri);
         } catch (IllegalArgumentException e) {
+            /* ignore */
         }
 
-
         try {
             cr.update(uri, cv, NAME_EQ_PLACEHOLDER, new String[]{name});
-            fail("SettingsProvider didn't throw IllegalArgumentException for update name "
+            fail("SettingsProvider didn't throw SecurityException for update name "
                     + name + " at URI " + uri);
         } catch (IllegalArgumentException e) {
+            /* ignore */
         }
 
         try {
-            Cursor c = cr.query(uri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
+            cr.query(uri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
                     new String[]{name}, null);
             fail("SettingsProvider didn't throw IllegalArgumentException for query name "
                     + name + " at URI " + uri);
         } catch (IllegalArgumentException e) {
+            /* ignore */
         }
 
 
@@ -235,6 +164,7 @@
             fail("SettingsProvider didn't throw IllegalArgumentException for delete name "
                     + name + " at URI " + uri);
         } catch (IllegalArgumentException e) {
+            /* ignore */
         }
 
 
@@ -259,9 +189,7 @@
 
     public void testAccessNonTable() {
         tryBadTableAccess("SYSTEM", "system", "install_non_market_apps");
-        tryBadTableAccess("BOOKMARKS", "bookmarks", "install_non_market_apps");
         tryBadTableAccess("SECURE", "secure", "install_non_market_apps");
-        tryBadTableAccess("BLUETOOTH_DEVICES", "bluetooth_devices", "install_non_market_apps");
         tryBadTableAccess(" secure", "secure", "install_non_market_apps");
         tryBadTableAccess("secure ", "secure", "install_non_market_apps");
         tryBadTableAccess(" secure ", "secure", "install_non_market_apps");
diff --git a/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java b/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java
index 2052e2e..96ea1d0 100644
--- a/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java
+++ b/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java
@@ -53,9 +53,6 @@
 
         selection = System.NAME + "=\"" + STRING_FIELD + "\"";
         cr.delete(System.CONTENT_URI, selection, null);
-
-        selection = System.NAME + "=\"" + System.SHOW_GTALK_SERVICE_STATUS + "\"";
-        cr.delete(System.CONTENT_URI, selection, null);
     }
 
     public void testSystemSettings() throws SettingNotFoundException {
@@ -76,16 +73,15 @@
 
             String stringValue = "cts";
 
-            // insert 5 rows, and update 1 rows
+            // insert 4 rows, and update 1 rows
             assertTrue(System.putInt(cr, INT_FIELD, 10));
             assertTrue(System.putLong(cr, LONG_FIELD, 20l));
             assertTrue(System.putFloat(cr, FLOAT_FIELD, 30.0f));
             assertTrue(System.putString(cr, STRING_FIELD, stringValue));
-            System.setShowGTalkServiceStatus(cr, true);
 
             c = cr.query(System.CONTENT_URI, null, null, null, null);
             assertNotNull(c);
-            assertEquals(origCount + 5, c.getCount());
+            assertEquals(origCount + 4, c.getCount());
             c.close();
 
             // get these rows to assert
@@ -94,7 +90,6 @@
             assertEquals(30.0f, System.getFloat(cr, FLOAT_FIELD), 0.001);
 
             assertEquals(stringValue, System.getString(cr, STRING_FIELD));
-            assertTrue(System.getShowGTalkServiceStatus(cr));
 
             // delete the tested rows again
             deleteTestedRows();
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
new file mode 100644
index 0000000..c74dbc0
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript.cts;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Type;
+import java.util.Random;
+
+public class AllocationCopyPaddedTest extends RSBaseCompute {
+    public void test_AllocationPadded_Byte3_1D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);;
+        int arr_len = width * 3;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_1D_Padded_Byte Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Byte3_2D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int arr_len = width * height * 3;
+        
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_2D_AllocationCopyTo_Padded_Byte Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Byte3_3D() {
+        Random random = new Random(0x172d8ab9);
+        int w = random.nextInt(32);
+        int h = random.nextInt(32);
+        int d = random.nextInt(32);
+        int arr_len = w * d * h * 3;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8_3(mRS));
+        typeBuilder.setX(w).setY(h).setZ(d);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_3D_Padded_Byte Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Short3_1D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_1D_Padded_Short Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Short3_2D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int arr_len = width * height * 3;
+        
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_2D_Padded_Short Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Short3_3D() {
+        Random random = new Random(0x172d8ab9);
+        int w = random.nextInt(32);
+        int h = random.nextInt(32);
+        int d = random.nextInt(32);
+        int arr_len = w * d * h * 3;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16_3(mRS));
+        typeBuilder.setX(w).setY(h).setZ(d);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_3D_Padded_Short Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Int3_1D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_1D_Padded_Int Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Int3_2D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int arr_len = width * height * 3;
+        
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_2D_Padded_Int Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Int3_3D() {
+        Random random = new Random(0x172d8ab9);
+        int w = random.nextInt(32);
+        int h = random.nextInt(32);
+        int d = random.nextInt(32);
+        int arr_len = w * d * h * 3;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32_3(mRS));
+        typeBuilder.setX(w).setY(h).setZ(d);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_3D_Padded_Int Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Float3_1D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_1D_Padded_Float Failed, output array does not match input",
+                   result);
+    }
+    public void test_AllocationPadded_Float3_2D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int arr_len = width * height * 3;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_2D_Padded_Float Failed, output array does not match input",
+                   result);
+    }
+    public void test_AllocationPadded_Float3_3D() {
+        Random random = new Random(0x172d8ab9);
+        int w = random.nextInt(32);
+        int h = random.nextInt(32);
+        int d = random.nextInt(32);
+        int arr_len = w * d * h * 3;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32_3(mRS));
+        typeBuilder.setX(w).setY(h).setZ(d);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_3D_Padded_Float Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Double3_1D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        double[] inArray = new double[arr_len];
+        double[] outArray = new double[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (double)random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F64_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_1D_Padded_Double Failed, output array does not match input",
+                   result);
+    }
+    public void test_AllocationPadded_Double3_2D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int arr_len = width * height * 3;
+
+        double[] inArray = new double[arr_len];
+        double[] outArray = new double[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (double)random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F64_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_2D_Padded_Double Failed, output array does not match input",
+                   result);
+    }
+    public void test_AllocationPadded_Double3_3D() {
+        Random random = new Random(0x172d8ab9);
+        int w = random.nextInt(32);
+        int h = random.nextInt(32);
+        int d = random.nextInt(32);
+        int arr_len = w * d * h * 3;
+
+        double[] inArray = new double[arr_len];
+        double[] outArray = new double[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (double)random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F64_3(mRS));
+        typeBuilder.setX(w).setY(h).setZ(d);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_3D_Padded_Double Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Long3_1D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_1D_Padded_Long Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Long3_2D() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int arr_len = width * height * 3;
+        
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_2D_Padded_Long Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_Long3_3D() {
+        Random random = new Random(0x172d8ab9);
+        int w = random.nextInt(32);
+        int h = random.nextInt(32);
+        int d = random.nextInt(32);
+        int arr_len = w * d * h * 3;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64_3(mRS));
+        typeBuilder.setX(w).setY(h).setZ(d);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copyFrom(inArray);
+        alloc.copyTo(outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_AllocationCopyTo_3D_Padded_Long Failed, output array does not match input",
+                   result);
+    }
+
+
+    public void test_AllocationPadded_copy1DRangeTo_Byte3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeTo_Padded_Byte Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeTo_Short3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+        
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeTo_Padded_Short Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeTo_Int3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeTo_Padded_Int Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeTo_Float3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0f) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeTo_Padded_Float Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeTo_Long3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeTo_Padded_Long Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy2DRangeTo_Byte3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount * 3;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy2DRangeTo_Padded_Byte Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy2DRangeTo_Short3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount * 3;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+        
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy2DRangeTo_Padded_Short Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy2DRangeTo_Int3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount * 3;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy2DRangeTo_Padded_Int Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy2DRangeTo_Float3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount * 3;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy2DRangeTo_Padded_Float Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy2DRangeTo_Long3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount * 3;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64_3(mRS));
+        typeBuilder.setX(width).setY(height);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy2DRangeTo_Padded_Long Failed, output array does not match input",
+                   result);
+    }
+
+
+    public void test_AllocationPadded_copy1DRangeToUnchecked_Byte3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeToUnchecked_Padded_Byte Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeToUnchecked_Short3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+        
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeToUnchecked_Padded_Short Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeToUnchecked_Int3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeToUnchecked_1D_Padded_Int Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeToUnchecked_Float3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0f) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeToUnchecked_Padded_Float Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_AllocationPadded_copy1DRangeToUnchecked_Long3() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width * 3;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64_3(mRS));
+        typeBuilder.setX(width);
+        Allocation alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.setAutoPadding(true);
+        int offset = random.nextInt(width);
+        int count = width - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count * 3; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count * 3; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_copy1DRangeToUnchecked_Padded_Long Failed, output array does not match input",
+                   result);
+    }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyToTest.java b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyToTest.java
new file mode 100644
index 0000000..71c4f64
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyToTest.java
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript.cts;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Type;
+import java.util.Random;
+
+public class AllocationCopyToTest extends RSBaseCompute {
+    private Allocation alloc;
+
+    public void test_Allocationcopy1DRangeTo_Byte() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeTo_Byte failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeTo_Short() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeTo_Short failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeTo_Int() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeTo_Int failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeTo_Float() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0f) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeTo_Float failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeTo_Long() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeTo(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeTo_Long failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy2DRangeTo_Byte() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8(mRS));
+        typeBuilder.setX(width).setY(height);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy2DRangeTo_Byte failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy2DRangeTo_Short() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16(mRS));
+        typeBuilder.setX(width).setY(height);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy2DRangeTo_Short failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy2DRangeTo_Int() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
+        typeBuilder.setX(width).setY(height);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy2DRangeTo_Int failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy2DRangeTo_Float() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32(mRS));
+        typeBuilder.setX(width).setY(height);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy2DRangeTo_Float failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy2DRangeTo_Long() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(128);
+        int height = random.nextInt(128);
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int arr_len = xcount * ycount;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64(mRS));
+        typeBuilder.setX(width).setY(height);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy2DRangeFrom(xoff, yoff, xcount, ycount, inArray);
+        alloc.copy2DRangeTo(xoff, yoff, xcount, ycount, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy2DRangeTo_Long failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy3DRangeTo_Byte() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(64);
+        int height = random.nextInt(64);
+        int depth = random.nextInt(64);
+
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int zoff = random.nextInt(height);
+
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int zcount = depth - zoff;
+        int arr_len = xcount * ycount * zcount;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8(mRS));
+        typeBuilder.setX(width).setY(height).setZ(depth);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy3DRangeFrom(xoff, yoff, zoff, xcount, ycount, zcount, (Object)inArray);
+        alloc.copy3DRangeTo(xoff, yoff, zoff, xcount, ycount, zcount, (Object)outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                android.util.Log.v("Allocation CopyTo Test", "Failed: " + i + " " + inArray[i] + " " + outArray[i]);
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy3DRangeTo_Byte failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy3DRangeTo_Short() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(64);
+        int height = random.nextInt(64);
+        int depth = random.nextInt(64);
+
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int zoff = random.nextInt(height);
+
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int zcount = depth - zoff;
+        int arr_len = xcount * ycount * zcount;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16(mRS));
+        typeBuilder.setX(width).setY(height).setZ(depth);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy3DRangeFrom(xoff, yoff, zoff, xcount, ycount, zcount, (Object)inArray);
+        alloc.copy3DRangeTo(xoff, yoff, zoff, xcount, ycount, zcount, (Object)outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                android.util.Log.v("Allocation CopyTo Test", "Failed: " + i + " " + inArray[i] + " " + outArray[i]);
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy3DRangeTo_Short failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy3DRangeTo_Int() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(64);
+        int height = random.nextInt(64);
+        int depth = random.nextInt(64);
+
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int zoff = random.nextInt(height);
+
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int zcount = depth - zoff;
+        int arr_len = xcount * ycount * zcount;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
+        typeBuilder.setX(width).setY(height).setZ(depth);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy3DRangeFrom(xoff, yoff, zoff, xcount, ycount, zcount, (Object)inArray);
+        alloc.copy3DRangeTo(xoff, yoff, zoff, xcount, ycount, zcount, (Object)outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                android.util.Log.v("Allocation CopyTo Test", "Failed: " + i + " " + inArray[i] + " " + outArray[i]);
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy3DRangeTo_Int failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy3DRangeTo_Float() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(64);
+        int height = random.nextInt(64);
+        int depth = random.nextInt(64);
+
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int zoff = random.nextInt(height);
+
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int zcount = depth - zoff;
+        int arr_len = xcount * ycount * zcount;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32(mRS));
+        typeBuilder.setX(width).setY(height).setZ(depth);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy3DRangeFrom(xoff, yoff, zoff, xcount, ycount, zcount, (Object)inArray);
+        alloc.copy3DRangeTo(xoff, yoff, zoff, xcount, ycount, zcount, (Object)outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                android.util.Log.v("Allocation CopyTo Test", "Failed: " + i + " " + inArray[i] + " " + outArray[i]);
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy3DRangeTo_Float failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy3DRangeTo_Long() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(64);
+        int height = random.nextInt(64);
+        int depth = random.nextInt(64);
+
+        int xoff = random.nextInt(width);
+        int yoff = random.nextInt(height);
+        int zoff = random.nextInt(height);
+
+        int xcount = width - xoff;
+        int ycount = height - yoff;
+        int zcount = depth - zoff;
+        int arr_len = xcount * ycount * zcount;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64(mRS));
+        typeBuilder.setX(width).setY(height).setZ(depth);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        alloc.copy3DRangeFrom(xoff, yoff, zoff, xcount, ycount, zcount, (Object)inArray);
+        alloc.copy3DRangeTo(xoff, yoff, zoff, xcount, ycount, zcount, (Object)outArray);
+
+        boolean result = true;
+        for (int i = 0; i < arr_len; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                android.util.Log.v("Allocation CopyTo Test", "Failed: " + i + " " + inArray[i] + " " + outArray[i]);
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy3DRangeTo_Long failed, output array does not match input",
+                   result);
+    }
+
+
+
+    public void test_Allocationcopy1DRangeToUnchecked_Byte() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        byte[] inArray = new byte[arr_len];
+        byte[] outArray = new byte[arr_len];
+        random.nextBytes(inArray);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I8(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeToUnchecked_Byte failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeToUnchecked_Short() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        short[] inArray = new short[arr_len];
+        short[] outArray = new short[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = (short)random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I16(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeToUnchecked_Short failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeToUnchecked_Int() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        int[] inArray = new int[arr_len];
+        int[] outArray = new int[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextInt();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeToUnchecked_Int Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeToUnchecked_Float() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        float[] inArray = new float[arr_len];
+        float[] outArray = new float[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextFloat();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.F32(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0f) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeToUnchecked_Float Failed, output array does not match input",
+                   result);
+    }
+
+    public void test_Allocationcopy1DRangeToUnchecked_Long() {
+        Random random = new Random(0x172d8ab9);
+        int width = random.nextInt(512);
+        int arr_len = width;
+
+        long[] inArray = new long[arr_len];
+        long[] outArray = new long[arr_len];
+
+        for (int i = 0; i < arr_len; i++) {
+            inArray[i] = random.nextLong();
+        }
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I64(mRS));
+        typeBuilder.setX(width);
+        alloc = Allocation.createTyped(mRS, typeBuilder.create());
+        int offset = random.nextInt(arr_len);
+        int count = arr_len - offset;
+        alloc.copy1DRangeFrom(offset, count, inArray);
+        alloc.copy1DRangeToUnchecked(offset, count, outArray);
+
+        boolean result = true;
+        for (int i = 0; i < count; i++) {
+            if (inArray[i] != outArray[i]) {
+                result = false;
+                break;
+            }
+        }
+        for (int i = count; i < arr_len; i++) {
+            if (outArray[i] != 0) {
+                result = false;
+                break;
+            }
+        }
+        assertTrue("test_Allocationcopy1DRangeToUnchecked_Long Failed, output array does not match input",
+                   result);
+    }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/DebugContext.java b/tests/tests/renderscript/src/android/renderscript/cts/DebugContext.java
index 50a3560..5c71155 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/DebugContext.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/DebugContext.java
@@ -58,43 +58,37 @@
      * Test whether we are detect out-of-bounds allocation accesses
      * from an invokable.
      */
-    // TODO Temporarily disable the test.
-    public void dontTestDebugContextI() {
+    public void testDebugContextI() {
         setupDebugContext();
         Soob.invoke_write_i(7, 1);  // Write to invalid location.
-        for (int i = 0; i < 100; i++) {
-            Soob.invoke_write_i(9, 0);
-            mRS.finish();
-        }
 
         // Flush messages through the pipeline.
-        Soob.invoke_send_msg();
+        mRS.sendMessage(RS_MSG_TEST_FLUSH, null);
         waitForMessage();
 
         Soob.destroy();
         assertTrue(mRanErrorHandler);
-        checkForErrors();
+
+        // The context is dead at this point so make sure it's not reused
+        RenderScript.releaseAllContexts();
     }
 
     /**
      * Test whether we are detect out-of-bounds allocation accesses
      * from a kernel.
      */
-    // TODO Temporarily disable the test.
-    public void dontTestDebugContextK() {
+    public void testDebugContextK() {
         setupDebugContext();
         Soob.forEach_write_k(AUnused);  // Write to invalid location.
-        for (int i = 0; i < 100; i++) {
-            Soob.invoke_write_i(9, 0);
-            mRS.finish();
-        }
 
         // Flush messages through the pipeline.
-        Soob.invoke_send_msg();
+        mRS.sendMessage(RS_MSG_TEST_FLUSH, null);
         waitForMessage();
 
         Soob.destroy();
         assertTrue(mRanErrorHandler);
-        checkForErrors();
+
+        // The context is dead at this point so make sure it's not reused
+        RenderScript.releaseAllContexts();
     }
 }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/LaunchClip.java b/tests/tests/renderscript/src/android/renderscript/cts/LaunchClip.java
new file mode 100644
index 0000000..ac2e730
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/LaunchClip.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript.cts;
+
+import android.renderscript.*;
+
+
+
+public class LaunchClip extends RSBaseCompute {
+    Allocation mAPassFail;
+    Allocation mAin;
+    Allocation mAout;
+    ScriptC_launchclip mScript;
+
+    int[] mIn;
+    int[] mOut;
+    int[] mPassFail;
+
+    int mDimX = 0;
+    int mDimY = 0;
+    int mDimZ = 0;
+    boolean mHasFaces = false;
+    boolean mHasLods = false;
+    int mDimA0 = 0;
+    int mDimA1 = 0;
+    int mDimA2 = 0;
+    int mDimA3 = 0;
+    int mCellCount = 0;
+
+    void setup(boolean makeIn, boolean makeOut, int x, int y, int z, boolean face, boolean lods,
+               int a0, int a1, int a2, int a3) {
+
+        mDimX = x;
+        mDimY = y;
+        mDimZ = z;
+        mHasFaces = face;
+        mHasLods = lods;
+        mDimA0 = a0;
+        mDimA1 = a1;
+        mDimA2 = a2;
+        mDimA3 = a3;
+
+        mScript = new ScriptC_launchclip(mRS);
+        mScript.set_dimX(mDimX);
+        mScript.set_dimY(mDimY);
+        mScript.set_dimZ(mDimZ);
+        mScript.set_hasFaces(mHasFaces);
+        mScript.set_hasLod(mHasLods);
+        mScript.set_dimA0(mDimA0);
+        mScript.set_dimA1(mDimA1);
+        mScript.set_dimA2(mDimA2);
+        mScript.set_dimA3(mDimA3);
+
+        Type.Builder tb = new Type.Builder(mRS, Element.I32(mRS));
+        tb.setX(mDimX);
+        if (mDimY > 0) tb.setY(mDimY);
+        if (mDimZ > 0) tb.setZ(mDimZ);
+        if (mHasFaces) tb.setFaces(true);
+        if (mHasLods) tb.setMipmaps(true);
+        //if (mDimA0 != 0) tb.setArray(0, mDimA0);
+        //if (mDimA1 != 0) tb.setArray(1, mDimA1);
+        //if (mDimA2 != 0) tb.setArray(2, mDimA2);
+        //if (mDimA3 != 0) tb.setArray(3, mDimA3);
+        Type t = tb.create();
+
+        if (makeIn) {
+            mIn = new int[t.getCount()];
+            mAin = Allocation.createTyped(mRS, t);
+            mScript.forEach_zero(mAin);
+        }
+        if (makeOut) {
+            mOut = new int[t.getCount()];
+            mAout = Allocation.createTyped(mRS, t);
+            mScript.forEach_zero(mAout);
+        }
+
+        mPassFail = new int[1];
+        mAPassFail = Allocation.createSized(mRS, Element.U32(mRS), 1);
+        mAPassFail.copyFrom(mPassFail);
+        mScript.set_passfail(mAPassFail);
+    }
+
+    private void verifyCell(int x, int y, int z, int[] a, Script.LaunchOptions sc) {
+        int expected = 0x80000000;
+        boolean inRange = true;
+
+        if (mDimX != 0) {
+            if (x >= sc.getXStart() && x < sc.getXEnd()) {
+                expected |= x;
+            } else {
+                inRange = false;
+            }
+        }
+
+        if (mDimY != 0) {
+            if (y >= sc.getYStart() && y < sc.getYEnd()) {
+                expected |= y << 8;
+            } else {
+                inRange = false;
+            }
+        }
+
+        if (mDimZ != 0) {
+            if (z >= sc.getZStart() && z < sc.getZEnd()) {
+                expected |= z << 16;
+            } else {
+                inRange = false;
+            }
+        }
+
+        if (!inRange) {
+            expected = 0;
+        }
+
+        int val = a[x + y * mDimX + z * mDimX * mDimY];
+        if (val != expected) {
+            String s = new String("verify error @ " + x + ", " + y + ", " + z +
+                                  ", expected " + expected + ", got " + val);
+            ///android.util.Log.e("rs", s);
+            throw new IllegalStateException(s);
+        }
+    }
+
+    void verifyRange(Script.LaunchOptions sc, int[] a) {
+        int itY = (mDimY > 0) ? mDimY : 1;
+        int itZ = (mDimZ > 0) ? mDimZ : 1;
+
+        for (int x = 0; x < mDimX; x++) {
+            for (int y = 0; y < itY; y++) {
+                for (int z = 0; z < itZ; z++) {
+                    verifyCell(x, y, z, a, sc);
+                }
+            }
+        }
+    }
+
+    AllocationAdapter makeAdapter(Allocation base, int ax, int ay, int az, int ox, int oy, int oz) {
+        Type.Builder tb = new Type.Builder(mRS, base.getType().getElement());
+        tb.setX(ax);
+        if (ay > 0) {
+            tb.setY(ay);
+        }
+        if (az > 0) {
+            tb.setZ(az);
+        }
+        Type t = tb.create();
+
+        AllocationAdapter a = AllocationAdapter.createTyped(mRS, base, t);
+        a.setX(ox);
+        if (base.getType().getY() > 0) {
+            a.setY(oy);
+        }
+        if (base.getType().getZ() > 0) {
+            a.setZ(oz);
+        }
+
+        mScript.set_biasX(ox);
+        mScript.set_biasY(oy);
+        mScript.set_biasZ(oz);
+        return a;
+    }
+
+    public void testWrite1D() {
+        setup(false, true, 256, 0, 0, false, false, 0, 0, 0, 0);
+        Script.LaunchOptions sc = new Script.LaunchOptions();
+        sc.setX(9, 77);
+
+        mScript.forEach_write1d(mAout, sc);
+        mAout.copyTo(mOut);
+
+        verifyRange(sc, mOut);
+    }
+
+    public void testWrite1DAdapter1D() {
+        setup(false, true, 256, 0, 0, false, false, 0, 0, 0, 0);
+        Script.LaunchOptions sc = new Script.LaunchOptions();
+        sc.setX(9, 77);
+
+        AllocationAdapter a = makeAdapter(mAout, 68, 0, 0,  9, 0, 0);
+        mScript.forEach_write1d(a);
+        mAout.copyTo(mOut);
+
+        verifyRange(sc, mOut);
+    }
+
+
+    public void testWrite2D() {
+        setup(false, true, 256, 256, 0, false, false, 0, 0, 0, 0);
+        Script.LaunchOptions sc = new Script.LaunchOptions();
+        sc.setX(9, 77);
+        sc.setY(17, 177);
+
+        mScript.forEach_write2d(mAout, sc);
+        mAout.copyTo(mOut);
+
+        verifyRange(sc, mOut);
+    }
+
+    public void testWrite2DAdapter1D() {
+        setup(false, true, 256, 256, 0, false, false, 0, 0, 0, 0);
+        Script.LaunchOptions sc = new Script.LaunchOptions();
+        sc.setX(9, 77);
+        sc.setY(17, 18);
+
+        AllocationAdapter a = makeAdapter(mAout, 68, 0, 0,  9, 17, 0);
+        mScript.forEach_write1d(a);
+        mAout.copyTo(mOut);
+
+        verifyRange(sc, mOut);
+    }
+
+    public void testWrite2DAdapter2D() {
+        setup(false, true, 256, 256, 0, false, false, 0, 0, 0, 0);
+        Script.LaunchOptions sc = new Script.LaunchOptions();
+        sc.setX(9, 77);
+        sc.setY(17, 177);
+
+        AllocationAdapter a = makeAdapter(mAout, 68, 160, 0,  9, 17, 0);
+        mScript.forEach_write2d(a);
+        mAout.copyTo(mOut);
+
+        verifyRange(sc, mOut);
+    }
+
+    public void testWrite3D() {
+        setup(false, true, 64, 64, 64, false, false, 0, 0, 0, 0);
+
+        Script.LaunchOptions sc = new Script.LaunchOptions();
+        sc.setX(9, 37);
+        sc.setY(17, 27);
+        sc.setZ(7, 21);
+        mScript.forEach_write3d(mAout, sc);
+        mAout.copyTo(mOut);
+
+        verifyRange(sc, mOut);
+    }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/RSBase.java b/tests/tests/renderscript/src/android/renderscript/cts/RSBase.java
index ebf15dc..0175c38 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/RSBase.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/RSBase.java
@@ -36,8 +36,9 @@
     private int result;
     private boolean msgHandled;
 
-    private static final int RS_MSG_TEST_PASSED = 100;
-    private static final int RS_MSG_TEST_FAILED = 101;
+    protected static final int RS_MSG_TEST_PASSED = 100;
+    protected static final int RS_MSG_TEST_FAILED = 101;
+    protected static final int RS_MSG_TEST_FLUSH = 102;
 
     RSMessageHandler mRsMessage = new RSMessageHandler() {
         public void run() {
@@ -47,6 +48,8 @@
                     case RS_MSG_TEST_FAILED:
                         result = mID;
                         break;
+                    case RS_MSG_TEST_FLUSH:
+                        break;
                     default:
                         fail("Got unexpected RS message");
                         return;
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java b/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
index 0413f22..6f15e16 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
@@ -39,10 +39,6 @@
 
     @Override
     protected void tearDown() throws Exception {
-        if (mRS != null) {
-            mRS.destroy();
-            mRS = null;
-        }
         super.tearDown();
     }
 
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/TestCtxDim.java b/tests/tests/renderscript/src/android/renderscript/cts/TestCtxDim.java
new file mode 100644
index 0000000..4a2af00
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/TestCtxDim.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript.cts;
+
+import android.renderscript.*;
+
+public class TestCtxDim extends RSBaseCompute {
+
+    public void test() {
+        ScriptC_TestCtxDim script = new ScriptC_TestCtxDim(mRS);
+
+        Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
+        int X = 2;
+        script.set_gDimX(X);
+        typeBuilder.setX(X);
+        int Y = 5;
+        script.set_gDimY(Y);
+        typeBuilder.setY(Y);
+        int Z = 11;
+        script.set_gDimZ(Z);
+        typeBuilder.setZ(Z);
+
+        Allocation A = Allocation.createTyped(mRS, typeBuilder.create());
+
+        script.forEach_check_kernel(A);
+        script.invoke_check_result();
+        mRS.finish();
+        waitForMessage();
+    }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/TestCtxDim.rs b/tests/tests/renderscript/src/android/renderscript/cts/TestCtxDim.rs
new file mode 100644
index 0000000..a3bbf3e
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/TestCtxDim.rs
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(android.renderscript.cts)
+
+#include "shared.rsh"
+
+int gDimX, gDimY, gDimZ;
+static bool failed = false;
+
+void __attribute__((kernel)) check_kernel(int32_t in /* dummy */, rs_kernel_context ctxt) {
+    uint32_t dimX = rsGetDimX(ctxt);
+    _RS_ASSERT(gDimX == dimX);
+    uint32_t dimY = rsGetDimY(ctxt);
+    _RS_ASSERT(gDimY == dimY);
+    uint32_t dimZ = rsGetDimZ(ctxt);
+    _RS_ASSERT(gDimZ == dimZ);
+}
+
+void check_result() {
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ThunkerCreateTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ThunkerCreateTest.java
new file mode 100644
index 0000000..735519c
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ThunkerCreateTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript.cts;
+
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import android.content.Context;
+import android.renderscript.RSRuntimeException;
+
+public class ThunkerCreateTest extends RSBase {
+
+    public void testCreateReflection() {
+        int sdkVersion = mCtx.getApplicationInfo().targetSdkVersion;
+
+        try {
+            Class<?> javaRS = Class.forName("android.renderscript.RenderScript");
+            Class[] signature = {Context.class, Integer.TYPE};
+            Object[] args = {mCtx, new Integer(sdkVersion)};
+            Method create = javaRS.getDeclaredMethod("create", signature);
+
+            assertTrue (create.invoke(null, args) != null);
+        }
+        catch (Exception e) {
+            throw new RSRuntimeException("Failure to create platform RenderScript context");
+        }
+
+    }
+}
+
+
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/launchclip.rs b/tests/tests/renderscript/src/android/renderscript/cts/launchclip.rs
new file mode 100644
index 0000000..ca34f4a
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/launchclip.rs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "shared.rsh"
+
+rs_allocation passfail;
+
+int dimX;
+int dimY;
+int dimZ;
+bool hasFaces;
+bool hasLod;
+int dimA0;
+int dimA1;
+int dimA2;
+int dimA3;
+
+int biasX = 0;
+int biasY = 0;
+int biasZ = 0;
+
+
+int RS_KERNEL zero() {
+    return 0;
+}
+
+int RS_KERNEL write1d(uint32_t x) {
+    return 0x80000000 | (x + biasX) | (biasY << 8) | (biasZ << 16);
+}
+
+int RS_KERNEL write2d(uint32_t x, uint32_t y) {
+    return 0x80000000 | (x + biasX) | ((y + biasY) << 8) | (biasZ << 16);
+}
+
+int RS_KERNEL write3d(uint32_t x, uint32_t y, uint32_t z) {
+    return 0x80000000 | (x + biasX) | ((y + biasY) << 8) | ((z + biasZ) << 16);
+}
+
+
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/oob.rs b/tests/tests/renderscript/src/android/renderscript/cts/oob.rs
index 11b7cef..d27a8ca 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/oob.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/oob.rs
@@ -10,6 +10,3 @@
     rsSetElementAt_int(aInt, 1, 1);
 }
 
-void send_msg() {
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
diff --git a/tests/tests/rscpp/librscpptest/rs_jni.cpp b/tests/tests/rscpp/librscpptest/rs_jni.cpp
index f5946f5..edfd7cc6 100644
--- a/tests/tests/rscpp/librscpptest/rs_jni.cpp
+++ b/tests/tests/rscpp/librscpptest/rs_jni.cpp
@@ -51,6 +51,18 @@
     }
 }
 
+sp<const Element> makeElement(sp<RS> rs, RsDataType dt, int vecSize) {
+    if (vecSize > 1) {
+        return Element::createVector(rs, dt, vecSize);
+    } else {
+        if (dt == RS_TYPE_UNSIGNED_8) {
+            return Element::U8(rs);
+        } else {
+            return Element::F32(rs);
+        }
+    }
+}
+
 extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSInitTest_initTest(JNIEnv * env,
                                                                                  jclass obj,
                                                                                  jstring pathObj)
@@ -371,4 +383,64 @@
 
 }
 
+extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSResizeTest_resizeTest(JNIEnv * env,
+                                                                                     jclass obj,
+                                                                                     jstring pathObj,
+                                                                                     jint X,
+                                                                                     jint Y,
+                                                                                     jfloat scaleX,
+                                                                                     jfloat scaleY,
+                                                                                     jboolean useByte,
+                                                                                     jint vecSize,
+                                                                                     jbyteArray inputByteArray,
+                                                                                     jbyteArray outputByteArray,
+                                                                                     jfloatArray inputFloatArray,
+                                                                                     jfloatArray outputFloatArray
+                                                                                     )
+{
+    const char * path = env->GetStringUTFChars(pathObj, NULL);
+
+    sp<RS> rs = new RS();
+    rs->init(path);
+
+    RsDataType dt = RS_TYPE_UNSIGNED_8;
+    if (!useByte) {
+        dt = RS_TYPE_FLOAT_32;
+    }
+    sp<const Element> e = makeElement(rs, dt, vecSize);
+    sp<Allocation> inputAlloc = Allocation::createSized2D(rs, e, X, Y);
+
+    int outX = (int) (X * scaleX);
+    int outY = (int) (Y * scaleY);
+    sp<Allocation> outputAlloc = Allocation::createSized2D(rs, e, outX, outY);
+    sp<ScriptIntrinsicResize> resize = ScriptIntrinsicResize::create(rs);
+
+    if (useByte) {
+        jbyte * input = (jbyte *) env->GetPrimitiveArrayCritical(inputByteArray, 0);
+        inputAlloc->copy2DRangeFrom(0, 0, X, Y, input);
+        env->ReleasePrimitiveArrayCritical(inputByteArray, input, 0);
+    } else {
+        jfloat * input = (jfloat *) env->GetPrimitiveArrayCritical(inputFloatArray, 0);
+        inputAlloc->copy2DRangeFrom(0, 0, X, Y, input);
+        env->ReleasePrimitiveArrayCritical(inputFloatArray, input, 0);
+    }
+
+    resize->setInput(inputAlloc);
+    resize->forEach_bicubic(outputAlloc);
+
+    if (useByte) {
+        jbyte * output = (jbyte *) env->GetPrimitiveArrayCritical(outputByteArray, 0);
+        outputAlloc->copy2DRangeTo(0, 0, outX, outY, output);
+        env->ReleasePrimitiveArrayCritical(outputByteArray, output, 0);
+    } else {
+        jfloat * output = (jfloat *) env->GetPrimitiveArrayCritical(outputFloatArray, 0);
+        outputAlloc->copy2DRangeTo(0, 0, outX, outY, output);
+        env->ReleasePrimitiveArrayCritical(outputFloatArray, output, 0);
+    }
+
+    env->ReleaseStringUTFChars(pathObj, path);
+    return (rs->getError() == RS_SUCCESS);
+
+}
+
 
diff --git a/tests/tests/rscpp/librscpptest/rs_jni_allocation.cpp b/tests/tests/rscpp/librscpptest/rs_jni_allocation.cpp
index 4157026..4b8b8a8 100644
--- a/tests/tests/rscpp/librscpptest/rs_jni_allocation.cpp
+++ b/tests/tests/rscpp/librscpptest/rs_jni_allocation.cpp
@@ -31,8 +31,8 @@
 
 using namespace android::RSC;
 
-static void createTypedHelper (sp<RS> mRS, sp<const Element> e) {
-    Type::Builder typeBuilder(mRS, e);
+static void createTypedHelper (sp<RS> rs, sp<const Element> e) {
+    Type::Builder typeBuilder(rs, e);
     for (int mips = 0; mips <= 1; mips ++) {
         bool useMips = (mips == 1);
 
@@ -45,7 +45,7 @@
                     typeBuilder.setFaces(useFaces);
                     typeBuilder.setX(x);
                     typeBuilder.setY(y);
-                    Allocation::createTyped(mRS, typeBuilder.create());
+                    Allocation::createTyped(rs, typeBuilder.create());
                 }
             }
         }
@@ -58,236 +58,147 @@
                                                                                         jstring pathObj)
 {
     const char * path = env->GetStringUTFChars(pathObj, NULL);
-    sp<RS> mRS = new RS();
-    mRS->init(path);
+    sp<RS> rs = new RS();
+    rs->init(path);
     env->ReleaseStringUTFChars(pathObj, path);
 
-    createTypedHelper(mRS, Element::A_8(mRS));
-    createTypedHelper(mRS, Element::RGBA_4444(mRS));
-    createTypedHelper(mRS, Element::RGBA_5551(mRS));
-    createTypedHelper(mRS, Element::RGB_565(mRS));
-    createTypedHelper(mRS, Element::RGB_888(mRS));
-    createTypedHelper(mRS, Element::RGBA_8888(mRS));
-    createTypedHelper(mRS, Element::F32(mRS));
-    createTypedHelper(mRS, Element::F32_2(mRS));
-    createTypedHelper(mRS, Element::F32_3(mRS));
-    createTypedHelper(mRS, Element::F32_4(mRS));
-    createTypedHelper(mRS, Element::F64(mRS));
-    createTypedHelper(mRS, Element::F64_2(mRS));
-    createTypedHelper(mRS, Element::F64_3(mRS));
-    createTypedHelper(mRS, Element::F64_4(mRS));
-    createTypedHelper(mRS, Element::I8(mRS));
-    createTypedHelper(mRS, Element::I8_2(mRS));
-    createTypedHelper(mRS, Element::I8_3(mRS));
-    createTypedHelper(mRS, Element::I8_4(mRS));
-    createTypedHelper(mRS, Element::I16(mRS));
-    createTypedHelper(mRS, Element::I16_2(mRS));
-    createTypedHelper(mRS, Element::I16_3(mRS));
-    createTypedHelper(mRS, Element::I16_4(mRS));
-    createTypedHelper(mRS, Element::I32(mRS));
-    createTypedHelper(mRS, Element::I32_2(mRS));
-    createTypedHelper(mRS, Element::I32_3(mRS));
-    createTypedHelper(mRS, Element::I32_4(mRS));
-    createTypedHelper(mRS, Element::I64(mRS));
-    createTypedHelper(mRS, Element::I64_2(mRS));
-    createTypedHelper(mRS, Element::I64_3(mRS));
-    createTypedHelper(mRS, Element::I64_4(mRS));
-    createTypedHelper(mRS, Element::U8(mRS));
-    createTypedHelper(mRS, Element::U8_2(mRS));
-    createTypedHelper(mRS, Element::U8_3(mRS));
-    createTypedHelper(mRS, Element::U8_4(mRS));
-    createTypedHelper(mRS, Element::U16(mRS));
-    createTypedHelper(mRS, Element::U16_2(mRS));
-    createTypedHelper(mRS, Element::U16_3(mRS));
-    createTypedHelper(mRS, Element::U16_4(mRS));
-    createTypedHelper(mRS, Element::U32(mRS));
-    createTypedHelper(mRS, Element::U32_2(mRS));
-    createTypedHelper(mRS, Element::U32_3(mRS));
-    createTypedHelper(mRS, Element::U32_4(mRS));
-    createTypedHelper(mRS, Element::U64(mRS));
-    createTypedHelper(mRS, Element::U64_2(mRS));
-    createTypedHelper(mRS, Element::U64_3(mRS));
-    createTypedHelper(mRS, Element::U64_4(mRS));
-    createTypedHelper(mRS, Element::MATRIX_2X2(mRS));
-    createTypedHelper(mRS, Element::MATRIX_3X3(mRS));
-    createTypedHelper(mRS, Element::MATRIX_4X4(mRS));
-    createTypedHelper(mRS, Element::SAMPLER(mRS));
-    createTypedHelper(mRS, Element::SCRIPT(mRS));
-    createTypedHelper(mRS, Element::TYPE(mRS));
-    createTypedHelper(mRS, Element::BOOLEAN(mRS));
-    createTypedHelper(mRS, Element::ELEMENT(mRS));
-    createTypedHelper(mRS, Element::ALLOCATION(mRS));
+    createTypedHelper(rs, Element::A_8(rs));
+    createTypedHelper(rs, Element::RGBA_4444(rs));
+    createTypedHelper(rs, Element::RGBA_5551(rs));
+    createTypedHelper(rs, Element::RGB_565(rs));
+    createTypedHelper(rs, Element::RGB_888(rs));
+    createTypedHelper(rs, Element::RGBA_8888(rs));
+    createTypedHelper(rs, Element::F32(rs));
+    createTypedHelper(rs, Element::F32_2(rs));
+    createTypedHelper(rs, Element::F32_3(rs));
+    createTypedHelper(rs, Element::F32_4(rs));
+    createTypedHelper(rs, Element::F64(rs));
+    createTypedHelper(rs, Element::F64_2(rs));
+    createTypedHelper(rs, Element::F64_3(rs));
+    createTypedHelper(rs, Element::F64_4(rs));
+    createTypedHelper(rs, Element::I8(rs));
+    createTypedHelper(rs, Element::I8_2(rs));
+    createTypedHelper(rs, Element::I8_3(rs));
+    createTypedHelper(rs, Element::I8_4(rs));
+    createTypedHelper(rs, Element::I16(rs));
+    createTypedHelper(rs, Element::I16_2(rs));
+    createTypedHelper(rs, Element::I16_3(rs));
+    createTypedHelper(rs, Element::I16_4(rs));
+    createTypedHelper(rs, Element::I32(rs));
+    createTypedHelper(rs, Element::I32_2(rs));
+    createTypedHelper(rs, Element::I32_3(rs));
+    createTypedHelper(rs, Element::I32_4(rs));
+    createTypedHelper(rs, Element::I64(rs));
+    createTypedHelper(rs, Element::I64_2(rs));
+    createTypedHelper(rs, Element::I64_3(rs));
+    createTypedHelper(rs, Element::I64_4(rs));
+    createTypedHelper(rs, Element::U8(rs));
+    createTypedHelper(rs, Element::U8_2(rs));
+    createTypedHelper(rs, Element::U8_3(rs));
+    createTypedHelper(rs, Element::U8_4(rs));
+    createTypedHelper(rs, Element::U16(rs));
+    createTypedHelper(rs, Element::U16_2(rs));
+    createTypedHelper(rs, Element::U16_3(rs));
+    createTypedHelper(rs, Element::U16_4(rs));
+    createTypedHelper(rs, Element::U32(rs));
+    createTypedHelper(rs, Element::U32_2(rs));
+    createTypedHelper(rs, Element::U32_3(rs));
+    createTypedHelper(rs, Element::U32_4(rs));
+    createTypedHelper(rs, Element::U64(rs));
+    createTypedHelper(rs, Element::U64_2(rs));
+    createTypedHelper(rs, Element::U64_3(rs));
+    createTypedHelper(rs, Element::U64_4(rs));
+    createTypedHelper(rs, Element::MATRIX_2X2(rs));
+    createTypedHelper(rs, Element::MATRIX_3X3(rs));
+    createTypedHelper(rs, Element::MATRIX_4X4(rs));
+    createTypedHelper(rs, Element::SAMPLER(rs));
+    createTypedHelper(rs, Element::SCRIPT(rs));
+    createTypedHelper(rs, Element::TYPE(rs));
+    createTypedHelper(rs, Element::BOOLEAN(rs));
+    createTypedHelper(rs, Element::ELEMENT(rs));
+    createTypedHelper(rs, Element::ALLOCATION(rs));
 
-    mRS->finish();
+    rs->finish();
     return true;
 }
 
-static bool helperFloatCopy(sp<RS> mRS, int nElems, int offset, int count, int copyMode) {
+static sp<const Element> makeElement(sp<RS> rs, RsDataType dt, int vecSize) {
+    if (vecSize > 1) {
+        return Element::createVector(rs, dt, vecSize);
+    } else {
+        return Element::createUser(rs, dt);
+    }
+}
+
+/**
+ * Test copyTo and copyFrom for all or part of a 1D Allocation.
+ *
+ * @param rs RS Context.
+ * @param cellCount Total number of elements in this Allocation.
+ * @param offset Offset of this Allocation for copy.
+ * @param count Number of elements need to copy.
+ * @param copyRange Copy the entire allocation or part of it (using different API).
+ * @param dt DataType intended to test.
+ * @param autoPadding Enable autoPadding or not. 
+*/
+template <class T>
+static bool helperCopy1D(sp<RS> rs, int cellCount, int offset, int count, bool copyRange,
+                         RsDataType dt, bool autoPadding = false) {
     bool passed = true;
-    sp<Allocation> A = Allocation::createSized(mRS, Element::F32(mRS), nElems);
+    int arrLen = cellCount;
+    int copyCount = count;
+    int iOffset = offset;
+    sp<Allocation> alloc = nullptr;
+
+    if (autoPadding) {
+        arrLen = cellCount * 3;
+        copyCount = count * 3;
+        iOffset = offset * 3;
+        alloc = Allocation::createSized(rs, makeElement(rs, dt, 3), cellCount);
+        alloc->setAutoPadding(autoPadding);
+    } else {
+        alloc = Allocation::createSized(rs, makeElement(rs, dt, 1), cellCount);
+    }
+
+    T* src = new T[arrLen];
+    T* dst = new T[arrLen];
+
+    for (int i = 0; i < copyCount; i++) {
+        src[i] = (T)rand();
+        dst[iOffset + i] = (T)(-1);
+    }
+
+    if (!copyRange) {
+        alloc->copy1DFrom(src);
+    } else {
+        alloc->copy1DRangeFrom(offset, count, src);
+    }
+    alloc->copy1DTo(dst);
+
+    for (int i = 0; i < copyCount; i++) {
+        if (dst[iOffset + i] != src[i]) {
+            passed = false;
+            break;
+        }
+    }
+
+    delete[] src;
+    delete[] dst;
+    return passed;
+}
+
+//Corresponding 1D allocation to allocation copy.
+static bool helperFloatAllocationCopy1D(sp<RS> rs, int cellCount, int offset, int count) {
+
+    bool passed = true;
+    sp<Allocation> srcA = Allocation::createSized(rs, Element::F32(rs), cellCount);
+    sp<Allocation> dstA = Allocation::createSized(rs, Element::F32(rs), cellCount);
 
     float *src, *dst;
-    src = new float[nElems];
-    dst = new float[nElems];
-
-    for (int i = 0; i < count; i++) {
-        src[i] = (float)i;
-        dst[offset + i] = -1.0f;
-    }
-
-    switch (copyMode) {
-    case 0: A->copy1DFrom(src); break;
-    case 1: A->copy1DRangeFrom(offset, count, src); break;
-    }
-    A->copy1DTo(dst);
-
-    for (int i = 0; i < count; i++) {
-        if (dst[offset + i] != src[i]) {
-            passed = false;
-            break;
-        }
-    }
-
-    delete[] src;
-    delete[] dst;
-    return passed;
-}
-
-static bool helperCharCopy(sp<RS> mRS, int nElems, int offset, int count, int copyMode) {
-    bool passed = true;
-    sp<Allocation> A = Allocation::createSized(mRS, Element::I8(mRS), nElems);
-
-    char *src, *dst;
-    src = new char[nElems];
-    dst = new char[nElems];
-
-    for (int i = 0; i < count; i++) {
-        src[i] = (char)i;
-        dst[offset + i] = -1;
-    }
-
-    switch (copyMode) {
-    case 0: A->copy1DFrom(src); break;
-    case 1: A->copy1DRangeFrom(offset, count, src); break;
-    }
-    A->copy1DTo(dst);
-
-    for (int i = 0; i < count; i++) {
-        if (dst[offset + i] != src[i]) {
-            passed = false;
-            break;
-        }
-    }
-
-    delete[] src;
-    delete[] dst;
-    return passed;
-}
-
-static bool helperShortCopy(sp<RS> mRS, int nElems, int offset, int count, int copyMode) {
-    bool passed = true;
-    sp<Allocation> A = Allocation::createSized(mRS, Element::I16(mRS), nElems);
-
-    short *src, *dst;
-    src = new short[nElems];
-    dst = new short[nElems];
-
-    for (int i = 0; i < count; i++) {
-        src[i] = (short)i;
-        dst[offset + i] = -1;
-    }
-
-    switch (copyMode) {
-    case 0: A->copy1DFrom(src); break;
-    case 1: A->copy1DRangeFrom(offset, count, src); break;
-    }
-    A->copy1DTo(dst);
-
-    for (int i = 0; i < count; i++) {
-        if (dst[offset + i] != src[i]) {
-            passed = false;
-            break;
-        }
-    }
-
-    delete[] src;
-    delete[] dst;
-    return passed;
-}
-
-static bool helperIntCopy(sp<RS> mRS, int nElems, int offset, int count, int copyMode) {
-    bool passed = true;
-    sp<Allocation> A = Allocation::createSized(mRS, Element::I32(mRS), nElems);
-
-    int *src, *dst;
-    src = new int[nElems];
-    dst = new int[nElems];
-
-    for (int i = 0; i < count; i++) {
-        src[i] = (int)i;
-        dst[offset + i] = -1;
-    }
-
-    switch (copyMode) {
-    case 0: A->copy1DFrom(src); break;
-    case 1: A->copy1DRangeFrom(offset, count, src); break;
-    }
-    A->copy1DTo(dst);
-
-    for (int i = 0; i < count; i++) {
-        if (dst[offset + i] != src[i]) {
-            passed = false;
-            break;
-        }
-    }
-
-    delete[] src;
-    delete[] dst;
-    return passed;
-}
-
-static bool helperDoubleCopy(sp<RS> mRS, int nElems, int offset, int count, int copyMode) {
-    bool passed = true;
-    sp<Allocation> A = Allocation::createSized(mRS, Element::F64(mRS), nElems);
-
-    double *src, *dst;
-    src = new double[nElems];
-    dst = new double[nElems];
-
-    for (int i = 0; i < count; i++) {
-        src[i] = (double)i;
-        dst[offset + i] = -1;
-    }
-
-    switch (copyMode) {
-    case 0: A->copy1DFrom(src); break;
-    case 1: A->copy1DRangeFrom(offset, count, src); break;
-    }
-    A->copy1DTo(dst);
-
-    for (int i = 0; i < count; i++) {
-        if (dst[offset + i] != src[i]) {
-            passed = false;
-            break;
-        }
-    }
-
-    delete[] src;
-    delete[] dst;
-    return passed;
-}
-
-static bool helperFloatAllocationCopy(sp<RS> mRS, int nElems, int offset, int count) {
-
-    bool passed = true;
-    sp<Allocation> srcA = Allocation::createSized(mRS, Element::F32(mRS), nElems);
-    sp<Allocation> dstA = Allocation::createSized(mRS, Element::F32(mRS), nElems);
-
-    float *src, *dst;
-    src = new float[nElems];
-    dst = new float[nElems];
-    for (int i = 0; i < nElems; i++) {
-        src[i] = (float)i;
+    src = new float[cellCount];
+    dst = new float[cellCount];
+    for (int i = 0; i < cellCount; i++) {
+        src[i] = (float)rand();
         dst[i] = -1.0f;
     }
 
@@ -309,6 +220,205 @@
     return passed;
 }
 
+/**
+ * Test copyTo and copyFrom for all or part of a 2D Allocation.
+ *
+ * @param rs RS Context.
+ * @param xElems Number of elements in X dimension in this Allocation.
+ * @param yElems Number of elements in Y dimension in this Allocation.
+ * @param xOffset Offset in X dimension of this Allocation for copy.
+ * @param yOffset Offset in Y dimension of this Allocation for copy.
+ * @param xCount Number of elements in X dimension need to copy.
+ * @param yCount Number of elements in Y dimension need to copy.
+ * @param dt DataType intended to test.
+ * @param autoPadding Enable autoPadding or not. 
+*/
+template <class T>
+static bool helperCopy2D(sp<RS> rs, int xElems, int yElems,
+                         int xOffset, int yOffset, int xCount, int yCount,
+                         RsDataType dt, bool autoPadding = false) {
+    bool passed = true;
+    int arrLen = xElems * yElems;
+    int copyCount = xCount * yCount;
+    sp<Allocation> alloc = nullptr;
+
+    if (autoPadding) {
+        arrLen = arrLen * 3;
+        copyCount = copyCount * 3;
+        alloc = Allocation::createSized2D(rs, makeElement(rs, dt, 3), xElems, yElems);
+        alloc->setAutoPadding(autoPadding);
+    } else {
+        alloc = Allocation::createSized2D(rs, makeElement(rs, dt, 1), xElems, yElems);
+    }
+
+    T* src = new T[arrLen];
+    T* dst = new T[arrLen];
+
+    for (int i = 0; i < copyCount; i++) {
+        src[i] = (T)rand();
+        dst[i] = (T)(-1);
+    }
+
+    alloc->copy2DRangeFrom(xOffset, yOffset, xCount, yCount, src);
+    alloc->copy2DRangeTo(xOffset, yOffset, xCount, yCount, dst);
+
+    for (int i = 0; i < copyCount; i++) {
+        if (dst[i] != src[i]) {
+            passed = false;
+            break;
+        }
+    }
+
+    delete[] src;
+    delete[] dst;
+    return passed;
+}
+
+//Corresponding 2D allocation to allocation copy.
+static bool helperFloatAllocationCopy2D(sp<RS> rs, int xElems, int yElems,
+                                        int xOffset, int yOffset, int xCount, int yCount) {
+
+    bool passed = true;
+    sp<Allocation> srcA = Allocation::createSized2D(rs, Element::F32(rs), xElems, yElems);
+    sp<Allocation> dstA = Allocation::createSized2D(rs, Element::F32(rs), xElems, yElems);
+
+    float *src, *dst;
+    src = new float[xElems * yElems];
+    dst = new float[xElems * yElems];
+    for (int i = 0; i < xCount * yCount; i++) {
+        src[i] = (float)rand();
+        dst[i] = -1.0f;
+    }
+
+    // First populate the source allocation
+    srcA->copy2DRangeFrom(xOffset, yOffset, xCount, yCount, src);
+    // Now test allocation to allocation copy
+    dstA->copy2DRangeFrom(xOffset, yOffset, xCount, yCount, srcA, xOffset, yOffset);
+    dstA->copy2DRangeTo(xOffset, yOffset, xCount, yCount, dst);
+
+    for (int i = 0; i < xCount * yCount; i++) {
+        if (dst[i] != src[i]) {
+            passed = false;
+            break;
+        }
+    }
+
+    delete[] src;
+    delete[] dst;
+    return passed;
+}
+
+/**
+ * Test copyTo and copyFrom for all or part of a 2D Allocation.
+ *
+ * @param rs RS Context.
+ * @param xElems Number of elements in X dimension in this Allocation.
+ * @param yElems Number of elements in Y dimension in this Allocation.
+ * @param zElems Number of elements in Z dimension in this Allocation.
+ * @param xOffset Offset in X dimension of this Allocation for copy.
+ * @param yOffset Offset in Y dimension of this Allocation for copy.
+ * @param zOffset Offset in Z dimension of this Allocation for copy.
+ * @param xCount Number of elements in X dimension need to copy.
+ * @param yCount Number of elements in Y dimension need to copy.
+ * @param zCount Number of elements in Z dimension need to copy.
+ * @param dt DataType intended to test.
+ * @param autoPadding Enable autoPadding or not. 
+*/
+template <class T>
+static bool helperCopy3D(sp<RS> rs, int xElems, int yElems, int zElems,
+                         int xOffset, int yOffset, int zOffset,
+                         int xCount, int yCount, int zCount,
+                         RsDataType dt, bool autoPadding = false) {
+    bool passed = true;
+    int arrLen = xElems * yElems * zElems;
+    int copyCount = xCount * yCount * zCount;
+    sp<Allocation> alloc = nullptr;
+
+    if (autoPadding) {
+        arrLen = arrLen * 3;
+        copyCount = copyCount * 3;
+
+        Type::Builder typeBuilder(rs, makeElement(rs, dt, 3));
+        typeBuilder.setX(xElems);
+        typeBuilder.setY(yElems);
+        typeBuilder.setZ(zElems);
+
+        alloc = Allocation::createTyped(rs, typeBuilder.create());
+        alloc->setAutoPadding(autoPadding);
+    } else {
+        Type::Builder typeBuilder(rs, makeElement(rs, dt, 1));
+        typeBuilder.setX(xElems);
+        typeBuilder.setY(yElems);
+        typeBuilder.setZ(zElems);
+
+        alloc = Allocation::createTyped(rs, typeBuilder.create());
+    }
+
+    T* src = new T[arrLen];
+    T* dst = new T[arrLen];
+
+    for (int i = 0; i < copyCount; i++) {
+        src[i] = (T)rand();
+        dst[i] = (T)(-1);
+    }
+
+    alloc->copy3DRangeFrom(xOffset, yOffset, zOffset, xCount, yCount, zCount, src);
+    alloc->copy3DRangeTo(xOffset, yOffset, zOffset, xCount, yCount, zCount, dst);
+
+    for (int i = 0; i < copyCount; i++) {
+        if (dst[i] != src[i]) {
+            passed = false;
+            break;
+        }
+    }
+
+    delete[] src;
+    delete[] dst;
+    return passed;
+}
+
+//Corresponding 3D allocation to allocation copy.
+static bool helperFloatAllocationCopy3D(sp<RS> rs, int xElems, int yElems, int zElems,
+                                        int xOffset, int yOffset, int zOffset,
+                                        int xCount, int yCount, int zCount) {
+
+    bool passed = true;
+    Type::Builder typeBuilder(rs, Element::F32(rs));
+
+    typeBuilder.setX(xElems);
+    typeBuilder.setY(yElems);
+    typeBuilder.setZ(zElems);
+
+    sp<Allocation> srcA = Allocation::createTyped(rs, typeBuilder.create());
+    sp<Allocation> dstA = Allocation::createTyped(rs, typeBuilder.create());
+
+    float *src, *dst;
+    src = new float[xElems * yElems * zElems];
+    dst = new float[xElems * yElems * zElems];
+    for (int i = 0; i < xCount * yCount * zCount; i++) {
+        src[i] = (float)rand();
+        dst[i] = -1.0f;
+    }
+
+    // First populate the source allocation
+    srcA->copy3DRangeFrom(xOffset, yOffset, zOffset, xCount, yCount, zCount, src);
+    // Now test allocation to allocation copy
+    dstA->copy3DRangeFrom(xOffset, yOffset, zOffset, xCount, yCount, zCount,
+                          srcA, xOffset, yOffset, zOffset);
+    dstA->copy3DRangeTo(xOffset, yOffset, zOffset, xCount, yCount, zCount, dst);
+
+    for (int i = 0; i < xCount * yCount * zCount; i++) {
+        if (dst[i] != src[i]) {
+            passed = false;
+            break;
+        }
+    }
+
+    delete[] src;
+    delete[] dst;
+    return passed;
+}
+
 static int elemsToTest = 20;
 
 extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSAllocationTest_test1DCopy(JNIEnv * env,
@@ -316,37 +426,180 @@
                                                                                          jstring pathObj)
 {
     const char * path = env->GetStringUTFChars(pathObj, NULL);
-    sp<RS> mRS = new RS();
-    mRS->init(path);
+    sp<RS> rs = new RS();
+    rs->init(path);
     env->ReleaseStringUTFChars(pathObj, path);
     bool passed = true;
 
     for (int s = 8; s <= elemsToTest; s += 2) {
-        for (int mode = 0; mode < 1; mode ++) {
-            passed &= helperFloatCopy(mRS, s, 0, s, mode);
-            passed &= helperCharCopy(mRS, s, 0, s, mode);
-            passed &= helperShortCopy(mRS, s, 0, s, mode);
-            passed &= helperIntCopy(mRS, s, 0, s, mode);
-            //helperBaseObjCopy(mRS, s, 0, s, mode);
-        }
+        passed &= helperCopy1D<float>(rs, s, 0, s, false, RS_TYPE_FLOAT_32);
+        passed &= helperCopy1D<char>(rs, s, 0, s, false, RS_TYPE_SIGNED_8);
+        passed &= helperCopy1D<short>(rs, s, 0, s, false, RS_TYPE_SIGNED_16);
+        passed &= helperCopy1D<int>(rs, s, 0, s, false, RS_TYPE_SIGNED_32);
+        passed &= helperCopy1D<double>(rs, s, 0, s, false, RS_TYPE_FLOAT_64);
 
         // now test copy range
-        for (int mode = 1; mode < 2; mode ++) {
-            for (int off = 0; off < s; off ++) {
-                for (int count = 1; count <= s - off; count ++) {
-                    passed &= helperFloatCopy(mRS, s, off, count, mode);
-                    passed &= helperCharCopy(mRS, s, off, count, mode);
-                    passed &= helperShortCopy(mRS, s, off, count, mode);
-                    passed &= helperIntCopy(mRS, s, off, count, mode);
-                    //helperBaseObjCopy(mRS, s, off, count, mode);
-                }
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperCopy1D<float>(rs, s, off, count, true, RS_TYPE_FLOAT_32);
+                passed &= helperCopy1D<char>(rs, s, off, count, true, RS_TYPE_SIGNED_8);
+                passed &= helperCopy1D<short>(rs, s, off, count, true, RS_TYPE_SIGNED_16);
+                passed &= helperCopy1D<int>(rs, s, off, count, true, RS_TYPE_SIGNED_32);
+                passed &= helperCopy1D<double>(rs, s, off, count, true, RS_TYPE_FLOAT_64);
             }
         }
 
         for (int off = 0; off < s; off ++) {
             for (int count = 1; count <= s - off; count ++) {
-                passed &= helperFloatAllocationCopy(mRS, s, off, count);
-                //helperByteAllocationCopy(mRS, s, off, count);
+                passed &= helperFloatAllocationCopy1D(rs, s, off, count);
+            }
+        }
+    }
+    return passed;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSAllocationTest_test2DCopy(JNIEnv * env,
+                                                                                         jclass obj,
+                                                                                         jstring pathObj)
+{
+    const char * path = env->GetStringUTFChars(pathObj, NULL);
+    sp<RS> rs = new RS();
+    rs->init(path);
+    env->ReleaseStringUTFChars(pathObj, path);
+    bool passed = true;
+
+    for (int s = 8; s <= elemsToTest; s += 2) {
+        // now test copy range
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperCopy2D<float>(rs, s, s, off, off, count, count, RS_TYPE_FLOAT_32);
+                passed &= helperCopy2D<char>(rs, s, s, off, off, count, count, RS_TYPE_SIGNED_8);
+                passed &= helperCopy2D<short>(rs, s, s, off, off, count, count, RS_TYPE_SIGNED_16);
+                passed &= helperCopy2D<int>(rs, s, s, off, off, count, count, RS_TYPE_SIGNED_32);
+                passed &= helperCopy2D<double>(rs, s, s, off, off, count, count, RS_TYPE_FLOAT_64);
+            }
+        }
+
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperFloatAllocationCopy2D(rs, s, s, off, off, count, count);
+            }
+        }
+    }
+    return passed;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSAllocationTest_test3DCopy(JNIEnv * env,
+                                                                                         jclass obj,
+                                                                                         jstring pathObj)
+{
+    const char * path = env->GetStringUTFChars(pathObj, NULL);
+    sp<RS> rs = new RS();
+    rs->init(path);
+    env->ReleaseStringUTFChars(pathObj, path);
+    bool passed = true;
+
+    for (int s = 8; s <= elemsToTest; s += 2) {
+        // now test copy range
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperCopy3D<float>(rs, s, s, s, off, off, off, count, count, count, RS_TYPE_FLOAT_32);
+                passed &= helperCopy3D<char>(rs, s, s, s, off, off, off, count, count, count, RS_TYPE_SIGNED_8);
+                passed &= helperCopy3D<short>(rs, s, s, s, off, off, off, count, count, count, RS_TYPE_SIGNED_16);
+                passed &= helperCopy3D<int>(rs, s, s, s, off, off, off, count, count, count, RS_TYPE_SIGNED_32);
+                passed &= helperCopy3D<double>(rs, s, s, s, off, off, off, count, count, count, RS_TYPE_FLOAT_64);
+            }
+        }
+
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperFloatAllocationCopy3D(rs, s, s, s, off, off, off, count, count, count);
+            }
+        }
+    }
+    return passed;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSAllocationTest_test1DCopyPadded(JNIEnv * env,
+                                                                                               jclass obj,
+                                                                                               jstring pathObj)
+{
+    const char * path = env->GetStringUTFChars(pathObj, NULL);
+    sp<RS> rs = new RS();
+    rs->init(path);
+    env->ReleaseStringUTFChars(pathObj, path);
+    bool passed = true;
+
+    for (int s = 8; s <= elemsToTest; s += 2) {
+        passed &= helperCopy1D<float>(rs, s, 0, s, false, RS_TYPE_FLOAT_32, true);
+        passed &= helperCopy1D<char>(rs, s, 0, s, false, RS_TYPE_SIGNED_8, true);
+        passed &= helperCopy1D<short>(rs, s, 0, s, false, RS_TYPE_SIGNED_16, true);
+        passed &= helperCopy1D<int>(rs, s, 0, s, false, RS_TYPE_SIGNED_32, true);
+        passed &= helperCopy1D<double>(rs, s, 0, s, false, RS_TYPE_FLOAT_64, true);
+
+        // now test copy range
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperCopy1D<float>(rs, s, off, count, true, RS_TYPE_FLOAT_32, true);
+                passed &= helperCopy1D<char>(rs, s, off, count, true, RS_TYPE_SIGNED_8, true);
+                passed &= helperCopy1D<short>(rs, s, off, count, true, RS_TYPE_SIGNED_16, true);
+                passed &= helperCopy1D<int>(rs, s, off, count, true, RS_TYPE_SIGNED_32, true);
+                passed &= helperCopy1D<double>(rs, s, off, count, true, RS_TYPE_FLOAT_64, true);
+            }
+        }
+    }
+    return passed;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSAllocationTest_test2DCopyPadded(JNIEnv * env,
+                                                                                               jclass obj,
+                                                                                               jstring pathObj)
+{
+    const char * path = env->GetStringUTFChars(pathObj, NULL);
+    sp<RS> rs = new RS();
+    rs->init(path);
+    env->ReleaseStringUTFChars(pathObj, path);
+    bool passed = true;
+
+    for (int s = 8; s <= elemsToTest; s += 2) {
+        // now test copy range
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperCopy2D<float>(rs, s, s, off, off, count, count, RS_TYPE_FLOAT_32, true);
+                passed &= helperCopy2D<char>(rs, s, s, off, off, count, count, RS_TYPE_SIGNED_8, true);
+                passed &= helperCopy2D<short>(rs, s, s, off, off, count, count, RS_TYPE_SIGNED_16, true);
+                passed &= helperCopy2D<int>(rs, s, s, off, off, count, count, RS_TYPE_SIGNED_32, true);
+                passed &= helperCopy2D<double>(rs, s, s, off, off, count, count, RS_TYPE_FLOAT_64, true);
+            }
+        }
+    }
+    return passed;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_android_cts_rscpp_RSAllocationTest_test3DCopyPadded(JNIEnv * env,
+                                                                                               jclass obj,
+                                                                                               jstring pathObj)
+{
+    const char * path = env->GetStringUTFChars(pathObj, NULL);
+    sp<RS> rs = new RS();
+    rs->init(path);
+    env->ReleaseStringUTFChars(pathObj, path);
+    bool passed = true;
+
+    for (int s = 8; s <= elemsToTest; s += 2) {
+        // now test copy range
+        for (int off = 0; off < s; off ++) {
+            for (int count = 1; count <= s - off; count ++) {
+                passed &= helperCopy3D<float>(rs, s, s, s, off, off, off, count, count, count,
+                                              RS_TYPE_FLOAT_32, true);
+                passed &= helperCopy3D<char>(rs, s, s, s, off, off, off, count, count, count,
+                                             RS_TYPE_SIGNED_8, true);
+                passed &= helperCopy3D<short>(rs, s, s, s, off, off, off, count, count, count,
+                                              RS_TYPE_SIGNED_16, true);
+                passed &= helperCopy3D<int>(rs, s, s, s, off, off, off, count, count, count,
+                                            RS_TYPE_SIGNED_32, true);
+                passed &= helperCopy3D<double>(rs, s, s, s, off, off, off, count, count, count,
+                                               RS_TYPE_FLOAT_64, true);
             }
         }
     }
@@ -358,19 +611,19 @@
                                                                                                jstring pathObj)
 {
     const char * path = env->GetStringUTFChars(pathObj, NULL);
-    sp<RS> mRS = new RS();
-    mRS->init(path);
+    sp<RS> rs = new RS();
+    rs->init(path);
     env->ReleaseStringUTFChars(pathObj, path);
 
     bool passed = true;
 
-    Type::Builder b(mRS, Element::I32(mRS));
+    Type::Builder b(rs, Element::I32(rs));
     b.setX(48);
-    sp<Allocation> largeArray = Allocation::createTyped(mRS, b.create());
+    sp<Allocation> largeArray = Allocation::createTyped(rs, b.create());
     b.setX(1);
-    sp<Allocation> singleElement = Allocation::createTyped(mRS, b.create());
+    sp<Allocation> singleElement = Allocation::createTyped(rs, b.create());
 
-    sp<ScriptC_setelementat> script = new ScriptC_setelementat(mRS);
+    sp<ScriptC_setelementat> script = new ScriptC_setelementat(rs);
 
     script->set_memset_toValue(1);
     script->forEach_memset(singleElement);
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSAllocationTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSAllocationTest.java
index 76dbfee..012e731 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSAllocationTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSAllocationTest.java
@@ -33,14 +33,39 @@
     }
 
     native boolean test1DCopy(String path);
-    public void testRSAllocationCopy() {
+    public void testRSAllocationCopy1D() {
         assertTrue(test1DCopy(this.getContext().getCacheDir().toString()));
     }
 
+    native boolean test2DCopy(String path);
+    public void testRSAllocationCopy2D() {
+        assertTrue(test2DCopy(this.getContext().getCacheDir().toString()));
+    }
+
+    native boolean test3DCopy(String path);
+    public void testRSAllocationCopy3D() {
+        assertTrue(test3DCopy(this.getContext().getCacheDir().toString()));
+    }
+
+    native boolean test1DCopyPadded(String path);
+    public void testRSAllocationCopy1DPadded() {
+        assertTrue(test1DCopyPadded(this.getContext().getCacheDir().toString()));
+    }
+
+    native boolean test2DCopyPadded(String path);
+    public void testRSAllocationCopy2DPadded() {
+        assertTrue(test2DCopyPadded(this.getContext().getCacheDir().toString()));
+    }
+
+    native boolean test3DCopyPadded(String path);
+    public void testRSAllocationCopy3DPadded() {
+        assertTrue(test3DCopyPadded(this.getContext().getCacheDir().toString()));
+    }
+
     native boolean testSetElementAt(String path);
     public void testRSAllocationSetElementAt() {
         assertTrue(testSetElementAt(this.getContext().getCacheDir().toString()));
     }
 
 
-}
\ No newline at end of file
+}
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java
index 9b09cc7..0b308cb 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java
@@ -25,6 +25,7 @@
 import android.renderscript.RenderScript;
 import android.renderscript.Allocation;
 import android.renderscript.Element;
+import android.renderscript.Type;
 import android.util.Log;
 
 public class RSCppTest extends AndroidTestCase {
@@ -73,6 +74,29 @@
         }
     };
 
+    protected Element makeElement(Element.DataType dt, int vecSize) {
+        Element e;
+        if (vecSize > 1) {
+            e = Element.createVector(mRS, dt, vecSize);
+        } else {
+            if (dt == Element.DataType.UNSIGNED_8) {
+                e = Element.U8(mRS);
+            } else {
+                e = Element.F32(mRS);
+            }
+        }
+        return e;
+    }
+
+    protected Allocation makeAllocation(int w, int h, Element e) {
+        Type.Builder tb = new Type.Builder(mRS, e);
+        tb.setX(w);
+        tb.setY(h);
+        Type t = tb.create();
+        Allocation a = Allocation.createTyped(mRS, t);
+        return a;
+    }
+
     protected void checkForErrors() {
         mRS.finish();
         mVerify.invoke_checkError();
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSResizeTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSResizeTest.java
new file mode 100644
index 0000000..b4864b5
--- /dev/null
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSResizeTest.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.cts.rscpp;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.renderscript.*;
+import android.util.Log;
+import java.lang.Integer;
+
+public class RSResizeTest extends RSCppTest {
+    static {
+        System.loadLibrary("rscpptest_jni");
+    }
+
+    private final int inX = 307;
+    private final int inY = 157;
+
+    native boolean resizeTest(String path, int w, int h, float scaleX, float scaleY,
+                              boolean useByte, int vecSize, byte[] inB, byte[] outB,
+                              float[] inF, float[] outF);
+    private void testReszie(int w, int h, Element.DataType dt, int vecSize, float scaleX, float scaleY) {
+
+        boolean useByte = false;
+        if (dt == Element.DataType.UNSIGNED_8) {
+            useByte = true;
+        }
+
+        Element e = makeElement(dt, vecSize);
+        Allocation rsInput = makeAllocation(w, h, e);
+
+        int arrSize = w * h * (vecSize == 3 ? 4 : vecSize);
+        int[] baseAlloc = new int[arrSize];
+        byte[] byteAlloc = null;
+        float[] floatAlloc = null;
+
+        RSUtils.genRandom(0x72727272, 255, 1, -128, baseAlloc);
+        if (useByte) {
+            byteAlloc = new byte[arrSize];
+            for (int i = 0; i < arrSize; i++) {
+                byteAlloc[i] = (byte)baseAlloc[i];
+            }
+            rsInput.copyFromUnchecked(byteAlloc);
+        } else {
+            //Float case
+            floatAlloc = new float[arrSize];
+            for (int i = 0; i < arrSize; i++) {
+                floatAlloc[i] = (float)baseAlloc[i];
+            }
+            rsInput.copyFromUnchecked(floatAlloc);
+        }
+
+        int outW = (int) (w*scaleX);
+        int outH = (int) (h*scaleY);
+
+        Allocation rsOutput = makeAllocation(outW, outH, e);
+        Allocation rsCppOutput = makeAllocation(outW, outH, e);
+
+        ScriptIntrinsicResize resize = ScriptIntrinsicResize.create(mRS);
+        resize.setInput(rsInput);
+        resize.forEach_bicubic(rsOutput);
+
+        int outArrSize = outW * outH * (vecSize == 3 ? 4 : vecSize);
+        byte[] nativeByteAlloc = new byte[outArrSize];
+        float[] nativeFloatAlloc = new float[outArrSize];
+        resizeTest(this.getContext().getCacheDir().toString().toString(), w, h, scaleX, scaleY,
+                   useByte, vecSize, byteAlloc, nativeByteAlloc, floatAlloc, nativeFloatAlloc);
+
+        if (useByte) {
+            rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        } else {
+            rsCppOutput.copyFromUnchecked(nativeFloatAlloc);
+        }
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
+    }
+
+    public void test_U8_4_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f);
+    }
+    public void test_U8_3_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f);
+    }
+    public void test_U8_2_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f);
+    }
+    public void test_U8_1_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f);
+    }
+
+    public void test_U8_4_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f);
+    }
+    public void test_U8_3_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f);
+    }
+    public void test_U8_2_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f);
+    }
+    public void test_U8_1_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f);
+    }
+
+    public void test_U8_4_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f);
+    }
+    public void test_U8_3_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f);
+    }
+    public void test_U8_2_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f);
+    }
+    public void test_U8_1_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f);
+    }
+
+    public void test_U8_4_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f);
+    }
+    public void test_U8_3_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f);
+    }
+    public void test_U8_2_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f);
+    }
+    public void test_U8_1_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f);
+    }
+
+    public void test_U8_4_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f);
+    }
+    public void test_U8_3_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f);
+    }
+    public void test_U8_2_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f);
+    }
+    public void test_U8_1_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f);
+    }
+
+    public void test_U8_4_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f);
+    }
+    public void test_U8_3_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f);
+    }
+    public void test_U8_2_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f);
+    }
+    public void test_U8_1_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f);
+    }
+
+    public void test_U8_4_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f);
+    }
+    public void test_U8_3_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f);
+    }
+    public void test_U8_2_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f);
+    }
+    public void test_U8_1_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f);
+    }
+
+    public void test_U8_4_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f);
+    }
+    public void test_U8_3_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f);
+    }
+    public void test_U8_2_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f);
+    }
+    public void test_U8_1_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f);
+    }
+
+    public void test_U8_4_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f);
+    }
+    public void test_U8_3_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f);
+    }
+    public void test_U8_2_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f);
+    }
+    public void test_U8_1_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f);
+    }
+
+    public void test_U8_4_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f);
+    }
+    public void test_U8_3_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f);
+    }
+    public void test_U8_2_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f);
+    }
+    public void test_U8_1_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f);
+    }
+
+
+    public void test_F32_4_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 4, 1.f, 1.f);
+    }
+    public void test_F32_3_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 3, 1.f, 1.f);
+    }
+    public void test_F32_2_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 2, 1.f, 1.f);
+    }
+    public void test_F32_1_SCALE10_10_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 1, 1.f, 1.f);
+    }
+
+    public void test_F32_4_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 2.f);
+    }
+    public void test_F32_3_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 2.f);
+    }
+    public void test_F32_2_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 2.f);
+    }
+    public void test_F32_1_SCALE20_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 2.f);
+    }
+
+    public void test_F32_4_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 2.f);
+    }
+    public void test_F32_3_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 2.f);
+    }
+    public void test_F32_2_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 2.f);
+    }
+    public void test_F32_1_SCALE05_20_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 2.f);
+    }
+
+    public void test_F32_4_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 0.5f);
+    }
+    public void test_F32_3_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 0.5f);
+    }
+    public void test_F32_2_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 0.5f);
+    }
+    public void test_F32_1_SCALE20_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 0.5f);
+    }
+
+    public void test_F32_4_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f);
+    }
+    public void test_F32_3_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f);
+    }
+    public void test_F32_2_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f);
+    }
+    public void test_F32_1_SCALE05_05_inSqure() {
+        testReszie(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f);
+    }
+
+    public void test_F32_4_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 4, 1.f, 1.f);
+    }
+    public void test_F32_3_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 3, 1.f, 1.f);
+    }
+    public void test_F32_2_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 2, 1.f, 1.f);
+    }
+    public void test_F32_1_SCALE10_10_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 1, 1.f, 1.f);
+    }
+
+    public void test_F32_4_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 2.f);
+    }
+    public void test_F32_3_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 2.f);
+    }
+    public void test_F32_2_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 2.f);
+    }
+    public void test_F32_1_SCALE20_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 2.f);
+    }
+
+    public void test_F32_4_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 2.f);
+    }
+    public void test_F32_3_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 2.f);
+    }
+    public void test_F32_2_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 2.f);
+    }
+    public void test_F32_1_SCALE05_20_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 2.f);
+    }
+
+    public void test_F32_4_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 0.5f);
+    }
+    public void test_F32_3_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 0.5f);
+    }
+    public void test_F32_2_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 0.5f);
+    }
+    public void test_F32_1_SCALE20_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 0.5f);
+    }
+
+    public void test_F32_4_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f);
+    }
+    public void test_F32_3_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f);
+    }
+    public void test_F32_2_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f);
+    }
+    public void test_F32_1_SCALE05_05_inRectangle() {
+        testReszie(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f);
+    }
+}
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index c41ee58..ec36d6d 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctstestrunner ctsdeviceutil guava
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
 
 LOCAL_JNI_SHARED_LIBRARIES := libctssecurity_jni libcts_jni
 
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 8ed74ba..25bc6ac 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -25,6 +25,7 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
 
         <service android:name="android.security.cts.SeccompDeathTestService"
                  android:process=":death_test_service"
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 46d0868..7106385 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -31,7 +31,6 @@
 		android_security_cts_SeccompDeathTestService.cpp \
 		android_security_cts_SELinuxTest.cpp \
 		android_security_cts_MMapExecutableTest.cpp \
-		android_security_cts_NetlinkSocket.cpp \
 		android_security_cts_AudioPolicyBinderTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index ca8e841..424dbaf 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -16,7 +16,6 @@
 
 #include <jni.h>
 #include <stdio.h>
-#include "android_security_cts_NetlinkSocket.h"
 
 extern int register_android_security_cts_KernelSettingsTest(JNIEnv*);
 extern int register_android_security_cts_CharDeviceTest(JNIEnv*);
@@ -67,10 +66,6 @@
         return JNI_ERR;
     }
 
-    if (register_android_security_cts_NetlinkSocket(env)) {
-        return JNI_ERR;
-    }
-
     if (register_android_security_cts_AudioPolicyBinderTest(env)) {
         return JNI_ERR;
     }
diff --git a/tests/tests/security/jni/android_security_cts_NetlinkSocket.cpp b/tests/tests/security/jni/android_security_cts_NetlinkSocket.cpp
deleted file mode 100644
index de315ea..0000000
--- a/tests/tests/security/jni/android_security_cts_NetlinkSocket.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#include <jni.h>
-#include <stdio.h>
-#include <cutils/log.h>
-#include <asm/types.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <errno.h>
-#include <string.h>
-#include "JNIHelp.h"
-
-#include "android_security_cts_NetlinkSocket.h"
-
-static void android_security_cts_NetlinkSocket_create(JNIEnv* env, jclass,
-    jobject fileDescriptor)
-{
-    int sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
-    if (sock == -1) {
-        ALOGE("Can't create socket %s", strerror(errno));
-        jclass SocketException = env->FindClass("java/net/SocketException");
-        env->ThrowNew(SocketException, "Can't create socket");
-        return;
-    }
-    jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
-}
-
-static int android_security_cts_NetlinkSocket_sendmsg(JNIEnv *e, jclass,
-    jobject fileDescriptor, jint pid, jbyteArray packet)
-{
-    void *bytes = (void *)e->GetByteArrayElements(packet, NULL);
-    uint32_t length = (uint32_t)e->GetArrayLength(packet);
-    struct sockaddr_nl snl;
-    struct iovec iov = {bytes, length};
-    struct msghdr msg = {&snl, sizeof(snl), &iov, 1, NULL, 0, 0};
-
-    memset(&snl, 0, sizeof(snl));
-    snl.nl_family = AF_NETLINK;
-    snl.nl_pid = pid;
-
-    int sock = jniGetFDFromFileDescriptor(e, fileDescriptor);
-    int retval = sendmsg(sock, &msg, 0);
-    e->ReleaseByteArrayElements(packet, (jbyte*)bytes, 0);
-    return retval;
-}
-
-
-static JNINativeMethod gMethods[] = {
-    {  "sendmsg", "(Ljava/io/FileDescriptor;I[B)I", (void *) android_security_cts_NetlinkSocket_sendmsg },
-    {  "create_native", "(Ljava/io/FileDescriptor;)V", (void *) android_security_cts_NetlinkSocket_create },
-};
-
-int register_android_security_cts_NetlinkSocket(JNIEnv* env)
-{
-    jclass clazz = env->FindClass("android/security/cts/NetlinkSocket");
-
-    return env->RegisterNatives(clazz, gMethods,
-            sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_NetlinkSocket.h b/tests/tests/security/jni/android_security_cts_NetlinkSocket.h
deleted file mode 100644
index 6e61c75..0000000
--- a/tests/tests/security/jni/android_security_cts_NetlinkSocket.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __ANDROID_SECURITY_CTS_H__
-#define __ANDROID_SECURITY_CTS_H__
-
-int register_android_security_cts_NetlinkSocket(JNIEnv*);
-
-#endif /* __ANDROID_SECURITY_CTS_H__ */
diff --git a/tests/tests/security/src/android/security/cts/KernelSettingsTest.java b/tests/tests/security/src/android/security/cts/KernelSettingsTest.java
index e401e41..9925e9d 100644
--- a/tests/tests/security/src/android/security/cts/KernelSettingsTest.java
+++ b/tests/tests/security/src/android/security/cts/KernelSettingsTest.java
@@ -115,6 +115,25 @@
 
     private static native boolean supportsXattr();
 
+    /**
+     * ICMP redirects should be disabled.
+     */
+    public void testNoIcmpRedirects() throws IOException {
+        try {
+            assertEquals("ICMP redirects are enabled for IPv4.",
+                    "0", getFile("/proc/sys/net/ipv4/conf/all/accept_redirects"));
+        } catch (FileNotFoundException e) {
+            // Odd. The file doesn't exist... Assume we're ok.
+        }
+
+        try {
+            assertEquals("ICMP redirects are enabled for IPv6.",
+                    "0", getFile("/proc/sys/net/ipv6/conf/all/accept_redirects"));
+        } catch (FileNotFoundException e) {
+            // Odd. The file doesn't exist... Assume we're ok.
+        }
+    }
+
     static String getFile(String filename) throws IOException {
         BufferedReader in = null;
         try {
diff --git a/tests/tests/security/src/android/security/cts/KeystoreExploitTest.java b/tests/tests/security/src/android/security/cts/KeystoreExploitTest.java
deleted file mode 100644
index 23266c2..0000000
--- a/tests/tests/security/src/android/security/cts/KeystoreExploitTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2011 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.security.cts;
-
-import android.test.AndroidTestCase;
-
-import java.io.File;
-import java.lang.reflect.Method;
-
-public class KeystoreExploitTest extends AndroidTestCase {
-    public void testKeystoreCrash() throws Exception {
-        int pid = Proc.findPidFor("/system/bin/keystore");
-
-        Class<?> keystoreClass = Class.forName("android.security.KeyStore");
-        Method getInstance = keystoreClass.getMethod("getInstance");
-        Method get = keystoreClass.getMethod("get", String.class);
-
-        Object keystore = getInstance.invoke(null);
-        String keyName = "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA";
-        get.invoke(keystore, keyName);
-
-        Thread.sleep(2000); // give keystore some time to crash
-
-        assertTrue("PID=" + pid + " crashed due to a malformed key name.",
-                new File("/proc/" + pid + "/cmdline").exists());
-    }
-}
diff --git a/tests/tests/security/src/android/security/cts/NetlinkSocket.java b/tests/tests/security/src/android/security/cts/NetlinkSocket.java
deleted file mode 100644
index 5ea80ca..0000000
--- a/tests/tests/security/src/android/security/cts/NetlinkSocket.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2011 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.security.cts;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.SocketException;
-
-public class NetlinkSocket {
-
-    static {
-        System.loadLibrary("ctssecurity_jni");
-    }
-
-    private static native void create_native(FileDescriptor fd) throws SocketException;
-    private static native int sendmsg(FileDescriptor fd, int pid, byte[] bytes);
-
-    private FileDescriptor fd = new FileDescriptor();
-
-    /** no public constructors */
-    private NetlinkSocket() { }
-
-    public static NetlinkSocket create() throws SocketException {
-        NetlinkSocket retval = new NetlinkSocket();
-        create_native(retval.fd);
-        return retval;
-    }
-
-    public boolean valid() {
-        return fd.valid();
-    }
-
-    public int sendmsg(int pid, byte[] bytes) throws IOException {
-        int retval = sendmsg(fd, pid, bytes);
-        if (retval == -1) {
-            throw new IOException("Unable to send message to PID=" + pid);
-        }
-        return retval;
-    }
-}
diff --git a/tests/tests/security/src/android/security/cts/Proc.java b/tests/tests/security/src/android/security/cts/Proc.java
deleted file mode 100644
index 6fe0706..0000000
--- a/tests/tests/security/src/android/security/cts/Proc.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011 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.security.cts;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-
-/**
- * Utilities for accessing /proc filesystem information.
- */
-public class Proc {
-    public static int findPidFor(String executable) throws IOException {
-        File f = new File("/proc");
-        for (File d : f.listFiles()) {
-            String cmdLineString = d.getAbsolutePath() + "/cmdline";
-            File cmdLine = new File(cmdLineString);
-            if (cmdLine.exists()) {
-                BufferedReader in = null;
-                try {
-                    in = new BufferedReader(new FileReader(cmdLine));
-                    String line = in.readLine();
-                    if ((line != null) && line.startsWith(executable)) {
-                        return Integer.decode(d.getName());
-                    }
-                } finally {
-                    if (in != null) {
-                        in.close();
-                    }
-                }
-            }
-        }
-        throw new RuntimeException("should never get here");
-    }
-}
diff --git a/tests/tests/security/src/android/security/cts/VoldExploitTest.java b/tests/tests/security/src/android/security/cts/VoldExploitTest.java
index 103158f..248579c 100644
--- a/tests/tests/security/src/android/security/cts/VoldExploitTest.java
+++ b/tests/tests/security/src/android/security/cts/VoldExploitTest.java
@@ -17,23 +17,9 @@
 package android.security.cts;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.os.storage.StorageManager;
 import android.test.AndroidTestCase;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Scanner;
-import java.util.Set;
-
 public class VoldExploitTest extends AndroidTestCase {
 
     /**
@@ -45,245 +31,4 @@
         String path = sm.getMountedObbPath("/dev/null\0asec list");
         assertNull(path);
     }
-
-    /**
-     * Validate that this device isn't vulnerable to the "ZergRush"
-     * vold vulnerability (CVE-2011-3874).
-     *
-     * https://github.com/revolutionary/zergRush/blob/master/zergRush.c
-     *
-     * Note: If the ZergRush vulnerability is present, the call to
-     * {@link StorageManager#getMountedObbPath(String)} below hangs until CTS
-     * kills the testsuite (10 minutes). A timeout, while not desirable,
-     * is the typical failure for this test.
-     */
-    public void testZergRushCrash() throws Exception {
-        int pid = Proc.findPidFor("/system/bin/vold");
-
-        StorageManager sm = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
-        sm.getMountedObbPath("AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA "
-                + "AAAA AAAA AAAA AAAA"
-                + "AAAA AAAA AAAA AAAA"
-                + "AAAA AAAA AAAA AAAA"
-                + "AAAA AAAA AAAA AAAA"
-                + "AAAA AAAA AAAA AAAA");
-
-        Thread.sleep(2000);  // give vold some time to crash
-
-        // Check to see if vold is still alive.
-        assertTrue(
-                "PID=" + pid + " crashed due to a malformed mount message."
-                        + " Detected unpatched ZergRush vulnerability (CVE-2011-3874).",
-                new File("/proc/" + pid + "/cmdline").exists());
-    }
-
-    /**
-     * Try to crash the vold program using CVE-2011-1823.
-     *
-     * This test attempts to send an invalid netlink messages to
-     * any process which is listening for the messages.  If we detect
-     * that any process crashed as a result of our message, then
-     * we know that we found a bug.
-     *
-     * If this test fails, it's due to CVE-2011-1823
-     *
-     * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-1823
-     */
-    public void testTryToCrashVold() throws IOException {
-        Set<Integer> pids = getPids();
-        assertTrue(pids.size() > 1);  // at least vold and netd should exist
-
-        Set<String> devices = new HashSet<String>();
-        devices.addAll(getSysFsPath("/etc/vold.fstab"));
-        devices.addAll(getSysFsPath("/system/etc/vold.fstab"));
-        if (devices.isEmpty()) {
-          // This vulnerability is not exploitable if there's
-          // no entry in vold.fstab
-          return;
-        }
-
-        NetlinkSocket ns;
-        try {
-            ns = NetlinkSocket.create();
-        } catch (SocketException e) {
-            // Can't create netlink socket. Not vulnerable.
-            return;
-        }
-        for (int i : pids) {
-            for (String j : devices) {
-                doAttack(ns, i, j);
-            }
-        }
-
-        // Check to see if all the processes are still alive.  If
-        // any of them have died, we found an exploitable bug.
-        for (int i : pids) {
-            assertTrue(
-                    "PID=" + i + " crashed due to a malformed netlink message."
-                    + " Detected unpatched vulnerability CVE-2011-1823.",
-                    new File("/proc/" + i + "/cmdline").exists());
-        }
-    }
-
-    /**
-     * Try to actually crash the program, by first sending a fake
-     * request to add a new disk, followed by a fake request to add
-     * a partition.
-     */
-    private static void doAttack(NetlinkSocket ns, int pid, String path)
-            throws IOException {
-        try {
-            ns.sendmsg(pid, getDiskAddedMessage(path));
-            confirmNetlinkMsgReceived();
-
-            for (int i = -1000; i > -5000; i-=1000) {
-                ns.sendmsg(pid, getPartitionAddedMessage(path, i));
-                confirmNetlinkMsgReceived();
-            }
-        } catch (IOException e) {
-            // Ignore the exception.  The process either:
-            //
-            // 1) Crashed
-            // 2) Closed the netlink socket and refused further messages
-            //
-            // If #1 occurs, our PID check in testTryToCrashVold() will
-            // detect the process crashed and trigger an error.
-            //
-            // #2 is not a security bug.  It's perfectly acceptable to
-            // refuse messages from someone trying to send you
-            // malicious content.
-        }
-    }
-
-    /**
-     * Parse the fstab.vold file, and extract out the "sysfs_path" field.
-     */
-    private static Set<String> getSysFsPath(String file) throws IOException {
-        Set<String> retval = new HashSet<String>();
-        File netlink = new File(file);
-        if (!netlink.canRead()) {
-            return retval;
-        }
-        Scanner scanner = null;
-        try {
-            scanner = new Scanner(netlink);
-            while(scanner.hasNextLine()) {
-                String line = scanner.nextLine().trim();
-                if (!line.startsWith("dev_mount")) {
-                    continue;
-                }
-
-                String[] fields = line.split("\\s+");
-                assertTrue(fields.length >= 5);
-                // Column 5 and beyond is "sysfs_path"
-                retval.addAll(Arrays.asList(fields).subList(4, fields.length));
-            }
-        } finally {
-            if (scanner != null) {
-                scanner.close();
-            }
-        }
-        return retval;
-    }
-
-    /**
-     * Poll /proc/net/netlink until all the "Rmem" fields contain
-     * "0" or approximately 10 seconds have passed.
-     *
-     * This indicates that either the netlink message was received,
-     * or the process took too long to process the incoming netlink
-     * message.
-     *
-     * See http://code.google.com/p/android/issues/detail?id=25099
-     * for information on why the timeout is needed.
-     */
-    private static void confirmNetlinkMsgReceived() {
-        try {
-            for (int ct = 0; ct < 200; ct++) {
-                boolean foundAllZeros = true;
-                for (List<String> i : parseNetlink()) {
-                    // Column 5 is the "Rmem" field, which is the
-                    // amount of kernel memory for received netlink messages.
-                    if (!i.get(4).equals("0")) {
-                        foundAllZeros = false;
-                    }
-                }
-                if (foundAllZeros) {
-                    return;
-                }
-                Thread.sleep(50);
-            }
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Extract all the PIDs listening for netlink messages.
-     */
-    private static Set<Integer> getPids() {
-        List<List<String>> netlink = parseNetlink();
-        Set<Integer> retval = new HashSet<Integer>();
-        for (List<String> i : netlink) {
-            // The PID is in column 3
-            int pid = Long.decode(i.get(2)).intValue();
-            if (new File("/proc/" + pid + "/cmdline").exists()) {
-                retval.add(pid);
-            }
-        }
-        return retval;
-    }
-
-    /**
-     * Parse /proc/net/netlink and return a List of lines
-     * (excluding the first line)
-     */
-    private static List<List<String>> parseNetlink() {
-        List<List<String>> retval = new ArrayList<List<String>>();
-        File netlink = new File("/proc/net/netlink");
-        Scanner scanner = null;
-        try {
-            scanner = new Scanner(netlink);
-            while(scanner.hasNextLine()) {
-                String line = scanner.nextLine().trim();
-                if (line.startsWith("sk")) {
-                    continue;
-                }
-
-                List<String> lineList = Arrays.asList(line.split("\\s+"));
-                retval.add(lineList);
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        } finally {
-            if (scanner != null) {
-                scanner.close();
-            }
-        }
-        return retval;
-    }
-
-    private static byte[] getDiskAddedMessage(String path) {
-        try {
-            return ("@/foo\0ACTION=add\0SUBSYSTEM=block\0"
-                    + "DEVPATH=" + path + "\0MAJOR=179\0MINOR=12345"
-                    + "\0DEVTYPE=disk\0").getBytes("ASCII");
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private static byte[] getPartitionAddedMessage(
-            String path, int partitionNum) {
-        try {
-            return ("@/foo\0ACTION=add\0SUBSYSTEM=block\0"
-                    + "DEVPATH=" + path + "\0MAJOR=179\0MINOR=12345"
-                    + "\0DEVTYPE=blah\0PARTN=" + partitionNum + "\0")
-                    .getBytes("ASCII");
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
 }
diff --git a/tests/tests/speech/Android.mk b/tests/tests/speech/Android.mk
index 6bec012..3ab78b8 100755
--- a/tests/tests/speech/Android.mk
+++ b/tests/tests/speech/Android.mk
@@ -27,6 +27,7 @@
 
 LOCAL_PACKAGE_NAME := CtsSpeechTestCases
 
-LOCAL_SDK_VERSION := current
+# Needed for testing M API
+#LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
index 5e6bb41..7b5baca 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
@@ -20,12 +20,17 @@
 import android.speech.tts.SynthesisRequest;
 import android.speech.tts.TextToSpeech;
 import android.speech.tts.TextToSpeechService;
+import android.util.Log;
 
 /**
  * Stub implementation of {@link TextToSpeechService}. Used for testing the
  * TTS engine API.
  */
 public class StubTextToSpeechService extends TextToSpeechService {
+    private static final String LOG_TAG = "StubTextToSpeechService";
+
+    // Object that onSynthesizeText will #wait on, if set to non-null
+    public static volatile Object sSynthesizeTextWait;
 
     @Override
     protected String[] onGetLanguage() {
@@ -51,6 +56,18 @@
         if (callback.start(16000, AudioFormat.ENCODING_PCM_16BIT, 1) != TextToSpeech.SUCCESS) {
             return;
         }
+
+        final Object synthesizeTextWait = sSynthesizeTextWait;
+        if (synthesizeTextWait != null) {
+            synchronized (synthesizeTextWait) {
+                try {
+                    synthesizeTextWait.wait(10000);  // 10s timeout
+                } catch (InterruptedException e) {
+                    Log.e(LOG_TAG, "onSynthesizeText wait interrupted", e);
+                }
+            }
+        }
+
         byte[] data = { 0x01, 0x2 };
         if (callback.audioAvailable(data, 0, data.length) != TextToSpeech.SUCCESS) {
             return;
diff --git a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
index c19f6c0..7425ecf 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
@@ -37,6 +37,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        StubTextToSpeechService.sSynthesizeTextWait = null;
         mTts = TextToSpeechWrapper.createTextToSpeechMockWrapper(getContext());
         assertNotNull(mTts);
     }
@@ -74,6 +75,31 @@
         assertTrue("speak() completion timeout", waitForUtterance());
     }
 
+    public void testSpeakStop() throws Exception {
+        final Object synthesizeTextWait = new Object();
+        StubTextToSpeechService.sSynthesizeTextWait = synthesizeTextWait;
+
+        getTts().stop();
+        final int iterations = 20;
+        for (int i = 0; i < iterations; i++) {
+            int result = getTts().speak(UTTERANCE, TextToSpeech.QUEUE_ADD, null,
+                    UTTERANCE_ID + Integer.toString(i));
+            assertEquals("speak() failed", TextToSpeech.SUCCESS, result);
+        }
+        getTts().stop();
+
+        // Wake up the Stubs #onSynthesizeSpeech (one that will be stopped in-progress)
+        synchronized (synthesizeTextWait) {
+          synthesizeTextWait.notify();
+        }
+
+        for (int i = 0; i < iterations; i++) {
+            assertTrue("speak() stop callback timeout", mTts.waitForStop(
+                    UTTERANCE_ID + Integer.toString(i)));
+        }
+    }
+
+
     public void testMediaPlayerFails() throws Exception {
         File sampleFile = new File(Environment.getExternalStorageDirectory(), "notsound.wav");
         try {
diff --git a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechTest.java b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechTest.java
index 69acdd0..c83304c 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechTest.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechTest.java
@@ -124,6 +124,22 @@
         assertTrue("speak() completion timeout", waitForUtterance());
     }
 
+
+    public void testSpeakStop() throws Exception {
+        getTts().stop();
+        final int iterations = 20;
+        for (int i = 0; i < iterations; i++) {
+            int result = getTts().speak(SAMPLE_TEXT, TextToSpeech.QUEUE_ADD, null,
+                    UTTERANCE_ID + Integer.toString(i));
+            assertEquals("speak() failed", TextToSpeech.SUCCESS, result);
+        }
+        getTts().stop();
+        for (int i = 0; i < iterations; i++) {
+            assertTrue("speak() stop callback timeout", mTts.waitForStop(
+                    UTTERANCE_ID + Integer.toString(i)));
+        }
+    }
+
     public void testGetEnginesIncludesDefault() throws Exception {
         if (mTts == null) {
             return;
diff --git a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java
index f0d55bf..9d460e2 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java
@@ -19,9 +19,10 @@
 import android.media.MediaPlayer;
 import android.speech.tts.TextToSpeech;
 import android.speech.tts.TextToSpeech.OnInitListener;
-import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
+import android.speech.tts.UtteranceProgressListener;
 import android.util.Log;
 
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
@@ -65,7 +66,7 @@
         if (!mInitListener.waitForInit()) {
             return false;
         }
-        mTts.setOnUtteranceCompletedListener(mUtteranceListener);
+        mTts.setOnUtteranceProgressListener(mUtteranceListener);
         return true;
     }
 
@@ -73,6 +74,10 @@
         return mUtteranceListener.waitForComplete(utteranceId);
     }
 
+    public boolean waitForStop(String utteranceId) throws InterruptedException {
+        return mUtteranceListener.waitForStop(utteranceId);
+    }
+
     public TextToSpeech getTts() {
         return mTts;
     }
@@ -139,12 +144,16 @@
     /**
      * Listener for waiting for utterance completion.
      */
-    private static class UtteranceWaitListener implements OnUtteranceCompletedListener {
+    private static class UtteranceWaitListener extends UtteranceProgressListener {
         private final Lock mLock = new ReentrantLock();
         private final Condition mDone  = mLock.newCondition();
+        private final HashSet<String> mStartedUtterances = new HashSet<String>();
+        private final HashSet<String> mStoppedUtterances = new HashSet<String>();
+        private final HashMap<String, Integer> mErredUtterances = new HashMap<String, Integer>();
         private final HashSet<String> mCompletedUtterances = new HashSet<String>();
 
-        public void onUtteranceCompleted(String utteranceId) {
+        @Override
+        public void onDone(String utteranceId) {
             mLock.lock();
             try {
                 mCompletedUtterances.add(utteranceId);
@@ -154,6 +163,49 @@
             }
         }
 
+        @Override
+        public void onError(String utteranceId) {
+            mLock.lock();
+            try {
+                mErredUtterances.put(utteranceId, -1);
+                mDone.signal();
+            } finally {
+                mLock.unlock();
+            }
+        }
+
+        @Override
+        public void onError(String utteranceId, int errorCode) {
+            mLock.lock();
+            try {
+                mErredUtterances.put(utteranceId, errorCode);
+                mDone.signal();
+            } finally {
+                mLock.unlock();
+            }
+        }
+
+        @Override
+        public void onStart(String utteranceId) {
+            mLock.lock();
+            try {
+                mStartedUtterances.add(utteranceId);
+            } finally {
+                mLock.unlock();
+            }
+        }
+
+        @Override
+        public void onStop(String utteranceId, boolean isStarted) {
+            mLock.lock();
+            try {
+                mStoppedUtterances.add(utteranceId);
+                mDone.signal();
+            } finally {
+                mLock.unlock();
+            }
+        }
+
         public boolean waitForComplete(String utteranceId)
                 throws InterruptedException {
             long timeOutNanos = TimeUnit.MILLISECONDS.toNanos(TTS_INIT_MAX_WAIT_TIME);
@@ -170,6 +222,23 @@
                 mLock.unlock();
             }
         }
+
+        public boolean waitForStop(String utteranceId)
+                throws InterruptedException {
+            long timeOutNanos = TimeUnit.MILLISECONDS.toNanos(TTS_INIT_MAX_WAIT_TIME);
+            mLock.lock();
+            try {
+                while (!mStoppedUtterances.remove(utteranceId)) {
+                    if (timeOutNanos <= 0) {
+                        return false;
+                    }
+                    timeOutNanos = mDone.awaitNanos(timeOutNanos);
+                }
+                return true;
+            } finally {
+                mLock.unlock();
+            }
+        }
     }
 
     /**
diff --git a/tests/tests/telephony/AndroidManifest.xml b/tests/tests/telephony/AndroidManifest.xml
index 31abf12..a87a54b 100644
--- a/tests/tests/telephony/AndroidManifest.xml
+++ b/tests/tests/telephony/AndroidManifest.xml
@@ -31,6 +31,9 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
 
     <application>
+        <provider android:name="android.telephony.cts.MmsPduProvider"
+                  android:authorities="telephonyctstest"
+                  android:grantUriPermissions="true" />
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
new file mode 100644
index 0000000..5b88525
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 android.telephony.cts;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.telephony.CellInfo;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Test TelephonyManager.getAllCellInfo()
+ * <p>
+ * TODO(chesnutt): test onCellInfoChanged() once the implementation
+ * of async callbacks is complete (see http://b/13788638)
+ */
+public class CellInfoTest extends AndroidTestCase{
+    private final Object mLock = new Object();
+    private TelephonyManager mTelephonyManager;
+    private static ConnectivityManager mCm;
+    private static final String TAG = "android.telephony.cts.CellInfoTest";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTelephonyManager =
+                (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
+        mCm = (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+    }
+
+    public void testCellInfo() throws Throwable {
+        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
+            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+            return;
+        }
+
+        // getAllCellInfo should never return null, and there should
+        // be at least one entry.
+        List<CellInfo> allCellInfo = mTelephonyManager.getAllCellInfo();
+        assertNotNull("TelephonyManager.getAllCellInfo() returned NULL!", allCellInfo);
+        assertTrue("TelephonyManager.getAllCellInfo() returned zero-length list!",
+            allCellInfo.size() > 0);
+    }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java b/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java
index c1f5757..9205f0e 100644
--- a/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java
@@ -60,6 +60,14 @@
             return;
         }
 
+        // getCellLocation should never return null,
+        // but that is allowed if the cell network type
+        // is LTE (since there is no LteCellLocation class)
+        if (mTelephonyManager.getNetworkType() != TelephonyManager.NETWORK_TYPE_LTE) {
+            assertNotNull("TelephonyManager.getCellLocation() returned null!",
+                mTelephonyManager.getCellLocation());
+        }
+
         CellLocation cl = CellLocation.getEmpty();
         if (cl instanceof GsmCellLocation) {
             GsmCellLocation gcl = (GsmCellLocation) cl;
diff --git a/tests/tests/telephony/src/android/telephony/cts/MmsPduProvider.java b/tests/tests/telephony/src/android/telephony/cts/MmsPduProvider.java
new file mode 100644
index 0000000..08164ee
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/MmsPduProvider.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.cts;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * A simple provider to send MMS PDU to platform MMS service
+ */
+public class MmsPduProvider extends ContentProvider {
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        // Not supported
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        // Not supported
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        // Not supported
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        // Not supported
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        // Not supported
+        return 0;
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String fileMode) throws FileNotFoundException {
+        File file = new File(getContext().getCacheDir(), uri.getPath());
+        int mode = (TextUtils.equals(fileMode, "r") ? ParcelFileDescriptor.MODE_READ_ONLY :
+                ParcelFileDescriptor.MODE_WRITE_ONLY
+                        |ParcelFileDescriptor.MODE_TRUNCATE
+                        |ParcelFileDescriptor.MODE_CREATE);
+        return ParcelFileDescriptor.open(file, mode);
+    }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/MmsTest.java b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
new file mode 100644
index 0000000..176c50c
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.cts;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.telephony.SmsManager;
+import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.google.android.mms.ContentType;
+import com.google.android.mms.InvalidHeaderValueException;
+import com.google.android.mms.pdu.CharacterSets;
+import com.google.android.mms.pdu.EncodedStringValue;
+import com.google.android.mms.pdu.GenericPdu;
+import com.google.android.mms.pdu.PduBody;
+import com.google.android.mms.pdu.PduComposer;
+import com.google.android.mms.pdu.PduHeaders;
+import com.google.android.mms.pdu.PduParser;
+import com.google.android.mms.pdu.PduPart;
+import com.google.android.mms.pdu.SendConf;
+import com.google.android.mms.pdu.SendReq;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+/**
+ * Test sending MMS using {@link android.telephony.SmsManager}.
+ */
+public class MmsTest extends AndroidTestCase {
+    private static final String TAG = "MmsTest";
+
+    private static final String ACTION_MMS_SENT = "CTS_MMS_SENT_ACTION";
+    private static final long DEFAULT_EXPIRY_TIME = 7 * 24 * 60 * 60;
+    private static final int DEFAULT_PRIORITY = PduHeaders.PRIORITY_NORMAL;
+
+    private static final String SUBJECT = "CTS MMS Test";
+    private static final String MESSAGE_BODY = "CTS MMS test message body";
+    private static final String TEXT_PART_FILENAME = "text_0.txt";
+    private static final String sSmilText =
+            "<smil>" +
+                    "<head>" +
+                        "<layout>" +
+                            "<root-layout/>" +
+                            "<region height=\"100%%\" id=\"Text\" left=\"0%%\" top=\"0%%\" width=\"100%%\"/>" +
+                        "</layout>" +
+                    "</head>" +
+                    "<body>" +
+                        "<par dur=\"8000ms\">" +
+                            "<text src=\"%s\" region=\"Text\"/>" +
+                        "</par>" +
+                    "</body>" +
+            "</smil>";
+
+    private static final long SENT_TIMEOUT = 1000 * 60 * 5; // 5 minutes
+
+    private static final String PROVIDER_AUTHORITY = "telephonyctstest";
+
+    private Random mRandom;
+    private SentReceiver mSentReceiver;
+    private TelephonyManager mTelephonyManager;
+
+    private static class SentReceiver extends BroadcastReceiver {
+        private final Object mLock;
+        private boolean mSuccess;
+        private boolean mDone;
+
+        public SentReceiver() {
+            mLock = new Object();
+            mSuccess = false;
+            mDone = false;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.i(TAG, "Action " + intent.getAction());
+            if (!ACTION_MMS_SENT.equals(intent.getAction())) {
+                return;
+            }
+            final int resultCode = getResultCode();
+            if (resultCode == Activity.RESULT_OK) {
+                final byte[] response = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA);
+                if (response != null) {
+                    final GenericPdu pdu = new PduParser(
+                            response, shouldParseContentDisposition()).parse();
+                    if (pdu != null && pdu instanceof SendConf) {
+                        final SendConf sendConf = (SendConf) pdu;
+                        if (sendConf.getResponseStatus() == PduHeaders.RESPONSE_STATUS_OK) {
+                            mSuccess = true;
+                        } else {
+                            Log.e(TAG, "SendConf response status=" + sendConf.getResponseStatus());
+                        }
+                    } else {
+                        Log.e(TAG, "Not a SendConf: " +
+                                (pdu != null ? pdu.getClass().getCanonicalName() : "NULL"));
+                    }
+                } else {
+                    Log.e(TAG, "Empty response");
+                }
+            } else {
+                Log.e(TAG, "Failure result=" + resultCode);
+                if (resultCode == SmsManager.MMS_ERROR_HTTP_FAILURE) {
+                    final int httpError = intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, 0);
+                    Log.e(TAG, "HTTP failure=" + httpError);
+                }
+            }
+            synchronized (mLock) {
+                mDone = true;
+                mLock.notify();
+            }
+        }
+
+        public boolean waitForSuccess(long timeout) {
+            synchronized(mLock) {
+                final long startTime = SystemClock.elapsedRealtime();
+                long waitTime = timeout;
+                while (waitTime > 0) {
+                    try {
+                        mLock.wait(waitTime);
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                    if (mDone) {
+                        break;
+                    }
+                    waitTime = timeout - (SystemClock.elapsedRealtime() - startTime);
+                }
+                Log.i(TAG, "Wait for sent: done=" + mDone + ", success=" + mSuccess);
+                return mDone && mSuccess;
+            }
+
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mRandom = new Random();
+        mTelephonyManager =
+                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
+    public void testSendMmsMessage() {
+        if (!mTelephonyManager.isSmsCapable()) {
+            Log.i(TAG, "testSendMmsMessage skipped: not SMS capable");
+            return;
+        }
+
+        Log.i(TAG, "testSendMmsMessage");
+        final Context context = getContext();
+        // Register sent receiver
+        mSentReceiver = new SentReceiver();
+        context.registerReceiver(mSentReceiver, new IntentFilter(ACTION_MMS_SENT));
+        // Create local provider file for sending PDU
+        final String fileName = "send." + String.valueOf(Math.abs(mRandom.nextLong())) + ".dat";
+        final File sendFile = new File(context.getCacheDir(), fileName);
+        final String selfNumber = getSimNumber(context);
+        assertTrue(!TextUtils.isEmpty(selfNumber));
+        final byte[] pdu = buildPdu(context, selfNumber, SUBJECT, MESSAGE_BODY);
+        assertNotNull(pdu);
+        assertTrue(writePdu(sendFile, pdu));
+        final Uri contentUri = (new Uri.Builder())
+                .authority(PROVIDER_AUTHORITY)
+                .path(fileName)
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .build();
+        // Send
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                context, 0, new Intent(ACTION_MMS_SENT), 0);
+        SmsManager.getDefault().sendMultimediaMessage(context,
+                contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
+        assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT));
+        sendFile.delete();
+    }
+
+    private static boolean writePdu(File file, byte[] pdu) {
+        FileOutputStream writer = null;
+        try {
+            writer = new FileOutputStream(file);
+            writer.write(pdu);
+            return true;
+        } catch (final IOException e) {
+            return false;
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    private byte[] buildPdu(Context context, String selfNumber, String subject, String text) {
+        final SendReq req = new SendReq();
+        // From, per spec
+        req.setFrom(new EncodedStringValue(selfNumber));
+        // To
+        final String[] recipients = new String[1];
+        recipients[0] = selfNumber;
+        final EncodedStringValue[] encodedNumbers = EncodedStringValue.encodeStrings(recipients);
+        if (encodedNumbers != null) {
+            req.setTo(encodedNumbers);
+        }
+        // Subject
+        if (!TextUtils.isEmpty(subject)) {
+            req.setSubject(new EncodedStringValue(subject));
+        }
+        // Date
+        req.setDate(System.currentTimeMillis() / 1000);
+        // Body
+        final PduBody body = new PduBody();
+        // Add text part. Always add a smil part for compatibility, without it there
+        // may be issues on some carriers/client apps
+        final int size = addTextPart(body, text, true/* add text smil */);
+        req.setBody(body);
+        // Message size
+        req.setMessageSize(size);
+        // Message class
+        req.setMessageClass(PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes());
+        // Expiry
+        req.setExpiry(DEFAULT_EXPIRY_TIME);
+        // The following set methods throw InvalidHeaderValueException
+        try {
+            // Priority
+            req.setPriority(DEFAULT_PRIORITY);
+            // Delivery report
+            req.setDeliveryReport(PduHeaders.VALUE_NO);
+            // Read report
+            req.setReadReport(PduHeaders.VALUE_NO);
+        } catch (InvalidHeaderValueException e) {
+            return null;
+        }
+
+        return new PduComposer(context, req).make();
+    }
+
+    private static int addTextPart(PduBody pb, String message, boolean addTextSmil) {
+        final PduPart part = new PduPart();
+        // Set Charset if it's a text media.
+        part.setCharset(CharacterSets.UTF_8);
+        // Set Content-Type.
+        part.setContentType(ContentType.TEXT_PLAIN.getBytes());
+        // Set Content-Location.
+        part.setContentLocation(TEXT_PART_FILENAME.getBytes());
+        int index = TEXT_PART_FILENAME.lastIndexOf(".");
+        String contentId = (index == -1) ? TEXT_PART_FILENAME
+                : TEXT_PART_FILENAME.substring(0, index);
+        part.setContentId(contentId.getBytes());
+        part.setData(message.getBytes());
+        pb.addPart(part);
+        if (addTextSmil) {
+            final String smil = String.format(sSmilText, TEXT_PART_FILENAME);
+            addSmilPart(pb, smil);
+        }
+        return part.getData().length;
+    }
+
+    private static void addSmilPart(PduBody pb, String smil) {
+        final PduPart smilPart = new PduPart();
+        smilPart.setContentId("smil".getBytes());
+        smilPart.setContentLocation("smil.xml".getBytes());
+        smilPart.setContentType(ContentType.APP_SMIL.getBytes());
+        smilPart.setData(smil.getBytes());
+        pb.addPart(0, smilPart);
+    }
+
+    private static String getSimNumber(Context context) {
+        final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        return telephonyManager.getLine1Number();
+    }
+
+    private static boolean shouldParseContentDisposition() {
+        return SmsManager
+                .getDefault()
+                .getCarrierConfigValues()
+                .getBoolean(SmsManager.MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, true);
+    }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java b/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java
index d96743c..4dcca0d 100644
--- a/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java
@@ -28,7 +28,10 @@
 import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
 import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
+import android.text.style.TtsSpan;
 
 import java.util.Locale;
 
@@ -326,4 +329,38 @@
         assertEquals("5567861616", PhoneNumberUtils.convertAndStrip("Ù¥‎ Ù¥‎Ù¦‎ Ù§‎ Ù¨‎ Ù¦‎ Ù¡‎ Ù¦‎ Ù¡‎ Ù¦‎"));
 
     }
+
+    public void testGetPhoneTtsSpan() {
+        // Setup: phone number without a country code. Lets keep coverage minimal to avoid
+        // exercising the underlying PhoneNumberUtil or constraining localization changes.
+        String phoneNumber = "6512223333";
+        // Execute
+        TtsSpan ttsSpan = PhoneNumberUtils.getPhoneTtsSpan(phoneNumber);
+        // Verify: the created TtsSpan contains the phone number.
+        assertEquals("6512223333", ttsSpan.getArgs().get(TtsSpan.ARG_NUMBER_PARTS));
+    }
+
+    public void testAddPhoneTtsSpan() {
+        // Setup: phone number without a country code. Lets keep coverage minimal to avoid
+        // exercising the underlying PhoneNumberUtil or constraining localization changes.
+        Spannable spannable = new SpannableString("Hello 6502223333");
+        // Execute
+        PhoneNumberUtils.addPhoneTtsSpan(spannable, 5, spannable.length() - 1);
+        // Verify: the Spannable is annotated with a TtsSpan in the correct location.
+        TtsSpan[] ttsSpans = spannable.getSpans(5, spannable.length() - 1, TtsSpan.class);
+        assertEquals(1, ttsSpans.length);
+        assertEquals("6502223333", ttsSpans[0].getArgs().get(TtsSpan.ARG_NUMBER_PARTS));
+    }
+
+    public void testGetPhoneTtsSpannable() {
+        // Setup: phone number without a country code. Lets keep coverage minimal to avoid
+        // exercising the underlying PhoneNumberUtil or constraining localization changes.
+        CharSequence phoneNumber = "6512223333";
+        // Execute
+        Spannable spannable = (Spannable) PhoneNumberUtils.getPhoneTtsSpannable(phoneNumber);
+        // Verify: returned char sequence contains a TtsSpan with the phone number in it
+        TtsSpan[] ttsSpans = spannable.getSpans(0, spannable.length() - 1, TtsSpan.class);
+        assertEquals(1, ttsSpans.length);
+        assertEquals("6512223333", ttsSpans[0].getArgs().get(TtsSpan.ARG_NUMBER_PARTS));
+    }
 }
diff --git a/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java b/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
index cb9d96c..68e71d1 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
@@ -221,7 +221,7 @@
     public void testGetPreferredNetworkType() {
         try {
             if (isSimCardPresent()) {
-                TelephonyManager.getDefault().getPreferredNetworkType();
+                TelephonyManager.getDefault().getPreferredNetworkType(0);
                 fail("Expected SecurityException. App doesn't have carrier privileges.");
             }
         } catch (SecurityException expected) {
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index b4fb8ab..3a64658 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -18,11 +18,20 @@
 
 import android.test.AndroidTestCase;
 import android.text.Editable;
+import android.text.GetChars;
+import android.text.GraphicsOperations;
+import android.text.Layout.Alignment;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
 import android.text.StaticLayout;
 import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
 import android.text.TextUtils;
-import android.text.Layout.Alignment;
+
+import java.text.Normalizer;
+import java.util.ArrayList;
+import java.util.List;
 
 public class StaticLayoutTest extends AndroidTestCase {
     private static final float SPACE_MULTI = 1.0f;
@@ -427,4 +436,409 @@
         assertTrue(layout.getLineContainsTab(0));
 
     }
+
+    // String wrapper for testing not well known implementation of CharSequence.
+    private class FakeCharSequence implements CharSequence {
+        private String mStr;
+
+        public FakeCharSequence(String str) {
+            mStr = str;
+        }
+
+        @Override
+        public char charAt(int index) {
+            return mStr.charAt(index);
+        }
+
+        @Override
+        public int length() {
+            return mStr.length();
+        }
+
+        @Override
+        public CharSequence subSequence(int start, int end) {
+            return mStr.subSequence(start, end);
+        }
+
+        @Override
+        public String toString() {
+            return mStr;
+        }
+    };
+
+    private List<CharSequence> buildTestCharSequences(String testString, Normalizer.Form[] forms) {
+        List<CharSequence> result = new ArrayList<CharSequence>();
+
+        List<String> normalizedStrings = new ArrayList<String>();
+        for (Normalizer.Form form: forms) {
+            normalizedStrings.add(Normalizer.normalize(testString, form));
+        }
+
+        for (String str: normalizedStrings) {
+            result.add(str);
+            result.add(new SpannedString(str));
+            result.add(new SpannableString(str));
+            result.add(new SpannableStringBuilder(str));  // as a GraphicsOperations implementation.
+            result.add(new FakeCharSequence(str));  // as a not well known implementation.
+        }
+        return result;
+    }
+
+    private String buildTestMessage(CharSequence seq) {
+        String normalized;
+        if (Normalizer.isNormalized(seq, Normalizer.Form.NFC)) {
+            normalized = "NFC";
+        } else if (Normalizer.isNormalized(seq, Normalizer.Form.NFD)) {
+            normalized = "NFD";
+        } else if (Normalizer.isNormalized(seq, Normalizer.Form.NFKC)) {
+            normalized = "NFKC";
+        } else if (Normalizer.isNormalized(seq, Normalizer.Form.NFKD)) {
+            normalized = "NFKD";
+        } else {
+            throw new IllegalStateException("Normalized form is not NFC/NFD/NFKC/NFKD");
+        }
+
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < seq.length(); ++i) {
+            builder.append(String.format("0x%04X ", Integer.valueOf(seq.charAt(i))));
+        }
+
+        return "testString: \"" + seq.toString() + "\"[" + builder.toString() + "]" +
+                ", class: " + seq.getClass().getName() +
+                ", Normalization: " + normalized;
+    }
+
+    public void testGetOffset_ASCII() {
+        String testStrings[] = { "abcde", "ab\ncd", "ab\tcd", "ab\n\nc", "ab\n\tc" };
+
+        for (String testString: testStrings) {
+            for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
+                StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                        DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+                String testLabel = buildTestMessage(seq);
+
+                assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+                assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+                assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2));
+                assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3));
+                assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4));
+                assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5));
+
+                assertEquals(testLabel, 1, layout.getOffsetToRightOf(0));
+                assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+                assertEquals(testLabel, 3, layout.getOffsetToRightOf(2));
+                assertEquals(testLabel, 4, layout.getOffsetToRightOf(3));
+                assertEquals(testLabel, 5, layout.getOffsetToRightOf(4));
+                assertEquals(testLabel, 5, layout.getOffsetToRightOf(5));
+            }
+        }
+
+        String testString = "ab\r\nde";
+        for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5));
+            assertEquals(testLabel, 5, layout.getOffsetToLeftOf(6));
+
+            assertEquals(testLabel, 1, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 5, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(5));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(6));
+        }
+    }
+
+    public void testGetOffset_UNICODE() {
+        String testStrings[] = new String[] {
+              // Cyrillic alphabets.
+              "\u0410\u0411\u0412\u0413\u0414",
+              // Japanese Hiragana Characters.
+              "\u3042\u3044\u3046\u3048\u304A",
+        };
+
+        for (String testString: testStrings) {
+            for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
+                StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                        DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+                String testLabel = buildTestMessage(seq);
+
+                assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+                assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+                assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2));
+                assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3));
+                assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4));
+                assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5));
+
+                assertEquals(testLabel, 1, layout.getOffsetToRightOf(0));
+                assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+                assertEquals(testLabel, 3, layout.getOffsetToRightOf(2));
+                assertEquals(testLabel, 4, layout.getOffsetToRightOf(3));
+                assertEquals(testLabel, 5, layout.getOffsetToRightOf(4));
+                assertEquals(testLabel, 5, layout.getOffsetToRightOf(5));
+            }
+        }
+    }
+
+    public void testGetOffset_UNICODE_Normalization() {
+        // "A" with acute, circumflex, tilde, diaeresis, ring above.
+        String testString = "\u00C1\u00C2\u00C3\u00C4\u00C5";
+        Normalizer.Form[] oneUnicodeForms = { Normalizer.Form.NFC, Normalizer.Form.NFKC };
+        for (CharSequence seq: buildTestCharSequences(testString, oneUnicodeForms)) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5));
+
+            assertEquals(testLabel, 1, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 3, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 5, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 5, layout.getOffsetToRightOf(5));
+        }
+
+        Normalizer.Form[] twoUnicodeForms = { Normalizer.Form.NFD, Normalizer.Form.NFKD };
+        for (CharSequence seq: buildTestCharSequences(testString, twoUnicodeForms)) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(6));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(7));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(8));
+            assertEquals(testLabel, 8, layout.getOffsetToLeftOf(9));
+            assertEquals(testLabel, 8, layout.getOffsetToLeftOf(10));
+
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(5));
+            assertEquals(testLabel, 8, layout.getOffsetToRightOf(6));
+            assertEquals(testLabel, 8, layout.getOffsetToRightOf(7));
+            assertEquals(testLabel, 10, layout.getOffsetToRightOf(8));
+            assertEquals(testLabel, 10, layout.getOffsetToRightOf(9));
+            assertEquals(testLabel, 10, layout.getOffsetToRightOf(10));
+        }
+    }
+
+    public void testGetOffset_UNICODE_SurrogatePairs() {
+        // Emoticons for surrogate pairs tests.
+        String testString =
+                "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03\uD83D\uDE04";
+        for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(6));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(7));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(8));
+            assertEquals(testLabel, 8, layout.getOffsetToLeftOf(9));
+            assertEquals(testLabel, 8, layout.getOffsetToLeftOf(10));
+
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(5));
+            assertEquals(testLabel, 8, layout.getOffsetToRightOf(6));
+            assertEquals(testLabel, 8, layout.getOffsetToRightOf(7));
+            assertEquals(testLabel, 10, layout.getOffsetToRightOf(8));
+            assertEquals(testLabel, 10, layout.getOffsetToRightOf(9));
+            assertEquals(testLabel, 10, layout.getOffsetToRightOf(10));
+        }
+    }
+
+    public void testGetOffset_UNICODE_Thai() {
+        // Thai Characters. The expected cursorable boundary is
+        // | \u0E02 | \u0E2D | \u0E1A | \u0E04\u0E38 | \u0E13 |
+        String testString = "\u0E02\u0E2D\u0E1A\u0E04\u0E38\u0E13";
+        for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 3, layout.getOffsetToLeftOf(5));
+            assertEquals(testLabel, 5, layout.getOffsetToLeftOf(6));
+
+            assertEquals(testLabel, 1, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 3, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 5, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 5, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(5));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(6));
+        }
+    }
+
+    public void testGetOffset_UNICODE_Hebrew() {
+        String testString = "\u05DE\u05E1\u05E2\u05D3\u05D4"; // Hebrew Characters
+        for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN,
+                    TextDirectionHeuristics.RTL, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 1, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 3, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 5, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 5, layout.getOffsetToLeftOf(5));
+
+            assertEquals(testLabel, 0, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 1, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 3, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(5));
+        }
+    }
+
+    public void testGetOffset_UNICODE_Arabic() {
+        // Arabic Characters. The expected cursorable boundary is
+        // | \u0623 \u064F | \u0633 \u0652 | \u0631 \u064E | \u0629 \u064C |";
+        String testString = "\u0623\u064F\u0633\u0652\u0631\u064E\u0629\u064C";
+
+        Normalizer.Form[] oneUnicodeForms = { Normalizer.Form.NFC, Normalizer.Form.NFKC };
+        for (CharSequence seq: buildTestCharSequences(testString, oneUnicodeForms)) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(5));
+            assertEquals(testLabel, 8, layout.getOffsetToLeftOf(6));
+            assertEquals(testLabel, 8, layout.getOffsetToLeftOf(7));
+            assertEquals(testLabel, 8, layout.getOffsetToLeftOf(8));
+
+            assertEquals(testLabel, 0, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 0, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(5));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(6));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(7));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(8));
+        }
+    }
+
+    public void testGetOffset_UNICODE_Bidi() {
+        // String having RTL characters and LTR characters
+
+        // LTR Context
+        // The first and last two characters are LTR characters.
+        String testString = "\u0061\u0062\u05DE\u05E1\u05E2\u0063\u0064";
+        // Logical order: [L1] [L2] [R1] [R2] [R3] [L3] [L4]
+        //               0    1    2    3    4    5    6    7
+        // Display order: [L1] [L2] [R3] [R2] [R1] [L3] [L4]
+        //               0    1    2    4    3    5    6    7
+        // [L?] means ?th LTR character and [R?] means ?th RTL character.
+        for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 3, layout.getOffsetToLeftOf(5));
+            assertEquals(testLabel, 5, layout.getOffsetToLeftOf(6));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(7));
+
+            assertEquals(testLabel, 1, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 5, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 3, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(5));
+            assertEquals(testLabel, 7, layout.getOffsetToRightOf(6));
+            assertEquals(testLabel, 7, layout.getOffsetToRightOf(7));
+        }
+
+        // RTL Context
+        // The first and last two characters are RTL characters.
+        String testString2 = "\u05DE\u05E1\u0063\u0064\u0065\u05DE\u05E1";
+        // Logical order: [R1] [R2] [L1] [L2] [L3] [R3] [R4]
+        //               0    1    2    3    4    5    6    7
+        // Display order: [R4] [R3] [L1] [L2] [L3] [R2] [R1]
+        //               7    6    5    3    4    2    1    0
+        // [L?] means ?th LTR character and [R?] means ?th RTL character.
+        for (CharSequence seq: buildTestCharSequences(testString2, Normalizer.Form.values())) {
+            StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
+                    DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+            String testLabel = buildTestMessage(seq);
+
+            assertEquals(testLabel, 1, layout.getOffsetToLeftOf(0));
+            assertEquals(testLabel, 2, layout.getOffsetToLeftOf(1));
+            assertEquals(testLabel, 4, layout.getOffsetToLeftOf(2));
+            assertEquals(testLabel, 5, layout.getOffsetToLeftOf(3));
+            assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4));
+            assertEquals(testLabel, 6, layout.getOffsetToLeftOf(5));
+            assertEquals(testLabel, 7, layout.getOffsetToLeftOf(6));
+            assertEquals(testLabel, 7, layout.getOffsetToLeftOf(7));
+
+            assertEquals(testLabel, 0, layout.getOffsetToRightOf(0));
+            assertEquals(testLabel, 0, layout.getOffsetToRightOf(1));
+            assertEquals(testLabel, 1, layout.getOffsetToRightOf(2));
+            assertEquals(testLabel, 4, layout.getOffsetToRightOf(3));
+            assertEquals(testLabel, 2, layout.getOffsetToRightOf(4));
+            assertEquals(testLabel, 3, layout.getOffsetToRightOf(5));
+            assertEquals(testLabel, 5, layout.getOffsetToRightOf(6));
+            assertEquals(testLabel, 6, layout.getOffsetToRightOf(7));
+        }
+    }
 }
diff --git a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
index 34ed2dc..b0fef51 100644
--- a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
@@ -86,6 +86,365 @@
         assertEquals(TEST_STRING, mTextView.getText().toString());
     }
 
+    private void executeCtrlBackspace(Editable content, MockBaseKeyListener listener) {
+        long currentTime = System.currentTimeMillis();
+        final KeyEvent delKeyEvent = new KeyEvent(
+                currentTime,
+                currentTime,
+                KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_DEL,
+                0 /* repeat */,
+                KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON);
+        listener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
+    }
+
+    private void assertCursorPosition(Editable content, int offset) {
+        assertEquals(offset, Selection.getSelectionStart(content));
+        assertEquals(offset, Selection.getSelectionEnd(content));
+    }
+
+    public void testBackspace_withCtrl() {
+        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+
+        // If the contents only having symbolic characters, delete all characters.
+        String testText = "!#$%&'()`{*}_?+";
+        Editable content = Editable.Factory.getInstance().newEditable(testText);
+        prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        // Latin ASCII text
+        testText = "Hello, World. This is Android.";
+        content = Editable.Factory.getInstance().newEditable(testText);
+
+        // If the cursor is head of the text, should do nothing.
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, World. This is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, World. This is ", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, World. This ", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, World. ", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, ", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        // Latin ASCII, cursor is middle of the text.
+        testText = "Hello, World. This is Android.";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        int charsFromTail = 12;  // Cursor location is 12 chars from the tail.(before "is").
+        prepTextViewSync(content, mockBaseKeyListener, false,
+                         testText.length() - charsFromTail, testText.length() - charsFromTail);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, World.  is Android.", content.toString());
+        assertCursorPosition(content, content.toString().length() - charsFromTail);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello,  is Android.", content.toString());
+        assertCursorPosition(content, content.toString().length() - charsFromTail);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals(" is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals(" is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        // Latin ASCII, cursor is inside word.
+        testText = "Hello, World. This is Android.";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        charsFromTail = 14;  // Cursor location is 12 chars from the tail. (inside "This")
+        prepTextViewSync(content, mockBaseKeyListener, false,
+                         testText.length() - charsFromTail, testText.length() - charsFromTail);
+
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, World. is is Android.", content.toString());
+        assertCursorPosition(content, content.toString().length() - charsFromTail);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("Hello, is is Android.", content.toString());
+        assertCursorPosition(content, content.toString().length() - charsFromTail);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("is is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("is is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        // Hebrew Text
+        // The deletion works on a Logical direction basis.
+        testText = "\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020" +
+                   "\u05D6\u05D4\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020" +
+                     "\u05D6\u05D4\u0020", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020",
+                     content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        // BiDi Text
+        // The deletion works on a Logical direction basis.
+        testText = "\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1" +
+                   "\u05D3\u0020\u05D4\u05D9\u05D8\u05D1\u002E";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1" +
+                     "\u05D3\u0020", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("\u05D6\u05D4\u0020", content.toString());
+        assertCursorPosition(content, content.toString().length());
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlBackspace(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+    }
+
+    private void executeCtrlForwardDelete(Editable content, MockBaseKeyListener listener) {
+        long currentTime = System.currentTimeMillis();
+        final KeyEvent delKeyEvent = new KeyEvent(
+                currentTime,
+                currentTime,
+                KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_FORWARD_DEL,
+                0 /* repeat */,
+                KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON);
+        listener.forwardDelete(mTextView, content, KeyEvent.KEYCODE_FORWARD_DEL, delKeyEvent);
+    }
+
+    public void testForwardDelete_withCtrl() {
+        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+
+        // If the contents only having symbolic characters, delete all characters.
+        String testText = "!#$%&'()`{*}_?+";
+        Editable content = Editable.Factory.getInstance().newEditable(testText);
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        // Latin ASCII text
+        testText = "Hello, World. This is Android.";
+        content = Editable.Factory.getInstance().newEditable(testText);
+
+        // If the cursor is tail of the text, should do nothing.
+        prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. This is Android.", content.toString());
+        assertCursorPosition(content, testText.length());
+
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals(", World. This is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals(". This is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals(" is Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals(" Android.", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals(".", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        // Latin ASCII, cursor is middle of the text.
+        testText = "Hello, World. This is Android.";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        int charsFromHead = 14;  // Cursor location is 14 chars from the head.(before "This").
+        prepTextViewSync(content, mockBaseKeyListener, false, charsFromHead, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World.  is Android.", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World.  Android.", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. .", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. ", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. ", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        // Latin ASCII, cursor is inside word.
+        testText = "Hello, World. This is Android.";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        charsFromHead = 16;  // Cursor location is 16 chars from the head. (inside "This")
+        prepTextViewSync(content, mockBaseKeyListener, false, charsFromHead, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. Th is Android.", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. Th Android.", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. Th.", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. Th", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("Hello, World. Th", content.toString());
+        assertCursorPosition(content, charsFromHead);
+
+        // Hebrew Text
+        // The deletion works on a Logical direction basis.
+        testText = "\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020" +
+                   "\u05D6\u05D4\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020\u05D6\u05D4\u0020\u05D0" +
+                     "\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u002E\u0020\u05D6\u05D4\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3" +
+                     "\u002E", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E",
+                     content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u002E", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        // BiDi Text
+        // The deletion works on a Logical direction basis.
+        testText = "\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1" +
+                   "\u05D3\u0020\u05D4\u05D9\u05D8\u05D1\u002E";
+        content = Editable.Factory.getInstance().newEditable(testText);
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1\u05D3\u0020" +
+                     "\u05D4\u05D9\u05D8\u05D1\u002E", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1\u05D3\u0020\u05D4\u05D9" +
+                     "\u05D8\u05D1\u002E", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u0020\u05E2\u05D5\u05D1\u05D3\u0020\u05D4\u05D9\u05D8\u05D1\u002E",
+                     content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u0020\u05D4\u05D9\u05D8\u05D1\u002E", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("\u002E", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+
+        executeCtrlForwardDelete(content, mockBaseKeyListener);
+        assertEquals("", content.toString());
+        assertCursorPosition(content, 0);
+    }
+
     /*
      * Check point:
      * 1. Press 0 key, the content of TextView does not changed.
diff --git a/tests/tests/uidisolation/Android.mk b/tests/tests/uidisolation/Android.mk
index 8529407..c21b6df 100644
--- a/tests/tests/uidisolation/Android.mk
+++ b/tests/tests/uidisolation/Android.mk
@@ -23,6 +23,8 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctstestserver
 
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsUidIsolationTestCases
diff --git a/tests/tests/uidisolation/AndroidManifest.xml b/tests/tests/uidisolation/AndroidManifest.xml
index a8c6848..86efb6f 100644
--- a/tests/tests/uidisolation/AndroidManifest.xml
+++ b/tests/tests/uidisolation/AndroidManifest.xml
@@ -18,6 +18,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.cts.uidisolation">
 
+    <uses-library android:name="org.apache.http.legacy" android:required="false" />
+
     <application android:label="UidIsolationTest">
       <activity android:name="android.uidisolation.cts.ServiceRunnerActivity"
                 android:label="UidIsolationTest"/>
diff --git a/tests/tests/uirendering/AndroidManifest.xml b/tests/tests/uirendering/AndroidManifest.xml
index 413dfba..b8d84a6 100644
--- a/tests/tests/uirendering/AndroidManifest.xml
+++ b/tests/tests/uirendering/AndroidManifest.xml
@@ -26,7 +26,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.cts.uirendering">
     </instrumentation>
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
index 117fe17..e092513 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
@@ -117,6 +117,7 @@
                     canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
                 }
                 canvas.drawBitmap(scaleUp ? mSmallGridBitmap : mBigGridBitmap, 0, 0, paint);
+                canvas.setDrawFilter(null);
             }
         };
         createTest()
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index e1c09f5..8c5f245 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -28,6 +28,8 @@
 import android.uirendering.cts.util.BitmapDumper;
 import android.util.Log;
 
+import android.support.test.InstrumentationRegistry;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -78,6 +80,10 @@
      */
     @Override
     public void setUp() {
+        // As the way to access Instrumentation is changed in the new runner, we need to inject it
+        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+        // be marked as deprecated and replaced with ActivityTestRule.
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
         mDifferenceVisualizer = new PassFailVisualizer();
         if (USE_RS) {
             mRenderScript = RenderScript.create(getActivity().getApplicationContext());
diff --git a/tests/tests/view/res/layout/inflater_override_theme_layout.xml b/tests/tests/view/res/layout/inflater_override_theme_layout.xml
index 2d2a578..93a765b 100644
--- a/tests/tests/view/res/layout/inflater_override_theme_layout.xml
+++ b/tests/tests/view/res/layout/inflater_override_theme_layout.xml
@@ -43,4 +43,13 @@
             android:theme="?attr/themeOverrideAttr" />
     </LinearLayout>
 
+    <include
+        layout="@layout/single_view_layout"
+        android:id="@+id/view_include"
+        android:theme="@style/Theme_OverrideInclude" />
+
+    <include
+        layout="@layout/single_view_layout"
+        android:id="@+id/view_include_notheme" />
+
 </LinearLayout>
diff --git a/tests/tests/view/res/layout/single_view_layout.xml b/tests/tests/view/res/layout/single_view_layout.xml
new file mode 100644
index 0000000..5f66983
--- /dev/null
+++ b/tests/tests/view/res/layout/single_view_layout.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:theme="@style/Theme_OverrideView" />
diff --git a/tests/tests/view/res/values/styles.xml b/tests/tests/view/res/values/styles.xml
index 20c80f8..9de4abd 100644
--- a/tests/tests/view/res/values/styles.xml
+++ b/tests/tests/view/res/values/styles.xml
@@ -150,6 +150,14 @@
     <style name="Theme_OverrideAttr">
         <item name="themeType">3</item>
     </style>
+
+    <style name="Theme_OverrideInclude">
+        <item name="themeType">4</item>
+    </style>
+
+    <style name="Theme_OverrideView">
+        <item name="themeType">5</item>
+    </style>
     
     <style name="Theme_ThemedDrawableTest">
         <item name="themeBoolean">true</item>
diff --git a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
index bf83086..59eefec 100644
--- a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
@@ -370,6 +370,8 @@
         verifyThemeType(container, "view_outer", R.id.view_outer, 1);
         verifyThemeType(container, "view_inner", R.id.view_inner, 2);
         verifyThemeType(container, "view_attr", R.id.view_attr, 3);
+        verifyThemeType(container, "view_include", R.id.view_include, 4);
+        verifyThemeType(container, "view_include_notheme", R.id.view_include_notheme, 5);
     }
 
     private void verifyThemeType(View container, String tag, int id, int type) {
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index ffbec1e..8194682 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -3582,6 +3582,11 @@
             return null;
         }
 
+        public ActionMode startActionModeForChild(View originalView,
+                ActionMode.Callback callback, int type) {
+            return null;
+        }
+
         public boolean hasShowContextMenuForChild() {
             return mHasShowContextMenuForChild;
         }
diff --git a/tests/tests/view/src/android/view/cts/WindowTest.java b/tests/tests/view/src/android/view/cts/WindowTest.java
index 3c5386d..dcfcfb7 100644
--- a/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -49,6 +49,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.SearchEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
@@ -1105,6 +1106,10 @@
             return mIsOnPanelClosedCalled;
         }
 
+        public boolean onSearchRequested(SearchEvent searchEvent) {
+            return onSearchRequested();
+        }
+
         public boolean onSearchRequested() {
             return false;
         }
@@ -1113,6 +1118,11 @@
             return null;
         }
 
+        public ActionMode onWindowStartingActionMode(
+                ActionMode.Callback callback, int type) {
+            return null;
+        }
+
         public void onActionModeStarted(ActionMode mode) {
         }
 
diff --git a/tests/tests/webkit/Android.mk b/tests/tests/webkit/Android.mk
index c2d8c3c..17a1f27 100644
--- a/tests/tests/webkit/Android.mk
+++ b/tests/tests/webkit/Android.mk
@@ -21,7 +21,7 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctsdeviceutillegacy ctstestserver ctstestrunner
 
diff --git a/tests/tests/webkit/AndroidManifest.xml b/tests/tests/webkit/AndroidManifest.xml
index a5bc2bb..098acd9 100644
--- a/tests/tests/webkit/AndroidManifest.xml
+++ b/tests/tests/webkit/AndroidManifest.xml
@@ -28,6 +28,7 @@
                   android:exported="true"
                   android:authorities="android.webkit.cts.MockContentProvider" />
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
 
         <activity android:name="android.webkit.cts.CookieSyncManagerCtsActivity"
             android:label="CookieSyncManagerCtsActivity"
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
index c612886..856b4aa 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
@@ -319,8 +319,6 @@
         assertFalse(anyDeleted.get());
     }
 
-    /*
-    TODO: uncomment when acceptThirdPartyCookies implementation lands
     public void testThirdPartyCookie() throws Throwable {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
@@ -377,7 +375,6 @@
             mOnUiThread.getSettings().setJavaScriptEnabled(false);
         }
     }
-    */
 
     public void testb3167208() throws Exception {
         if (!NullWebViewUtils.isWebViewAvailable()) {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index b381d72..634a318 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -122,6 +122,11 @@
      */
     private static final long SCROLL_WAIT_INTERVAL_MS = 200;
 
+    /**
+     * Epsilon used in page scale value comparisons.
+     */
+    private static final float PAGE_SCALE_EPSILON = 0.0001f;
+
     private WebView mWebView;
     private CtsTestServer mWebServer;
     private WebViewOnUiThread mOnUiThread;
@@ -330,7 +335,7 @@
         // that a scale change does *not* happen.
         Thread.sleep(500);
         currScale = mOnUiThread.getScale();
-        assertEquals(currScale, previousScale);
+        assertEquals(currScale, previousScale, PAGE_SCALE_EPSILON);
 
         assertTrue(mOnUiThread.zoomOut());
         previousScale = currScale;
@@ -354,7 +359,7 @@
         // that a scale change does *not* happen.
         Thread.sleep(500);
         currScale = mOnUiThread.getScale();
-        assertEquals(currScale, previousScale);
+        assertEquals(currScale, previousScale, PAGE_SCALE_EPSILON);
 
         mOnUiThread.zoomBy(1.25f);
         previousScale = currScale;
@@ -378,7 +383,7 @@
         // that a scale change does *not* happen.
         Thread.sleep(500);
         currScale = mOnUiThread.getScale();
-        assertEquals(currScale, previousScale);
+        assertEquals(currScale, previousScale, PAGE_SCALE_EPSILON);
 
         mOnUiThread.zoomBy(0.8f);
         previousScale = currScale;
@@ -402,7 +407,7 @@
         // that a scale change does *not* happen.
         Thread.sleep(500);
         currScale = mOnUiThread.getScale();
-        assertEquals(currScale, previousScale);
+        assertEquals(currScale, previousScale, PAGE_SCALE_EPSILON);
     }
 
     @UiThreadTest
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 480e1a6..2fedb29 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -40,6 +40,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.TouchUtils;
 import android.test.UiThreadTest;
@@ -85,6 +86,7 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
 import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
@@ -94,6 +96,7 @@
 import android.widget.TextView.OnEditorActionListener;
 
 import java.io.IOException;
+import java.util.Locale;
 
 /**
  * Test {@link TextView}.
@@ -128,6 +131,21 @@
         mInstrumentation = getInstrumentation();
     }
 
+    /**
+     * Promotes the TextView to editable and places focus in it to allow simulated typing.
+     */
+    private void initTextViewForTyping() {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView = findTextView(R.id.textview_text);
+                mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
+                mTextView.setText("", BufferType.EDITABLE);
+                mTextView.requestFocus();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
     public void testConstructor() {
         new TextView(mActivity);
 
@@ -1241,6 +1259,414 @@
         }
     }
 
+    public void testUndo_insert() {
+        initTextViewForTyping();
+
+        // Type some text.
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Precondition: The cursor is at the end of the text.
+                assertEquals(3, mTextView.getSelectionStart());
+
+                // Undo removes the typed string in one step.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+                assertEquals(0, mTextView.getSelectionStart());
+
+                // Redo restores the text and cursor position.
+                mTextView.onTextContextMenuItem(android.R.id.redo);
+                assertEquals("abc", mTextView.getText().toString());
+                assertEquals(3, mTextView.getSelectionStart());
+
+                // Undoing the redo clears the text again.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+
+                // Undo when the undo stack is empty does nothing.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_delete() {
+        initTextViewForTyping();
+
+        // Simulate deleting text and undoing it.
+        mInstrumentation.sendStringSync("xyz");
+        sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Precondition: The text was actually deleted.
+                assertEquals("", mTextView.getText().toString());
+                assertEquals(0, mTextView.getSelectionStart());
+
+                // Undo restores the typed string and cursor position in one step.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("xyz", mTextView.getText().toString());
+                assertEquals(3, mTextView.getSelectionStart());
+
+                // Redo removes the text in one step.
+                mTextView.onTextContextMenuItem(android.R.id.redo);
+                assertEquals("", mTextView.getText().toString());
+                assertEquals(0, mTextView.getSelectionStart());
+
+                // Undoing the redo restores the text again.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("xyz", mTextView.getText().toString());
+                assertEquals(3, mTextView.getSelectionStart());
+
+                // Undoing again undoes the original typing.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+                assertEquals(0, mTextView.getSelectionStart());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    // Initialize the text view for simulated IME typing. Must be called on UI thread.
+    private InputConnection initTextViewForSimulatedIme() {
+        mTextView = findTextView(R.id.textview_text);
+        mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
+        mTextView.setText("", BufferType.EDITABLE);
+        return mTextView.onCreateInputConnection(new EditorInfo());
+    }
+
+    // Simulates IME composing text behavior.
+    private void setComposingTextInBatch(InputConnection input, CharSequence text) {
+        input.beginBatchEdit();
+        input.setComposingText(text, 1);  // Leave cursor at end.
+        input.endBatchEdit();
+    }
+
+    @UiThreadTest
+    public void testUndo_imeInsertLatin() {
+        InputConnection input = initTextViewForSimulatedIme();
+
+        // Simulate IME text entry behavior. The Latin IME enters text by replacing partial words,
+        // such as "c" -> "ca" -> "cat" -> "cat ".
+        setComposingTextInBatch(input, "c");
+        setComposingTextInBatch(input, "ca");
+
+        // The completion and space are added in the same batch.
+        input.beginBatchEdit();
+        input.commitText("cat", 1);
+        input.commitText(" ", 1);
+        input.endBatchEdit();
+
+        // The repeated replacements undo in a single step.
+        mTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("", mTextView.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testUndo_imeInsertJapanese() {
+        InputConnection input = initTextViewForSimulatedIme();
+
+        // The Japanese IME does repeated replacements of Latin characters to hiragana to kanji.
+        final String HA = "\u306F";  // HIRAGANA LETTER HA
+        final String NA = "\u306A";  // HIRAGANA LETTER NA
+        setComposingTextInBatch(input, "h");
+        setComposingTextInBatch(input, HA);
+        setComposingTextInBatch(input, HA + "n");
+        setComposingTextInBatch(input, HA + NA);
+
+        // The result may be a surrogate pair. The composition ends in the same batch.
+        input.beginBatchEdit();
+        input.commitText("\uD83C\uDF37", 1);  // U+1F337 TULIP
+        input.setComposingText("", 1);
+        input.endBatchEdit();
+
+        // The repeated replacements are a single undo step.
+        mTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("", mTextView.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testUndo_imeCancel() {
+        InputConnection input = initTextViewForSimulatedIme();
+        mTextView.setText("flower");
+
+        // Start typing a composition.
+        final String HA = "\u306F";  // HIRAGANA LETTER HA
+        setComposingTextInBatch(input, "h");
+        setComposingTextInBatch(input, HA);
+        setComposingTextInBatch(input, HA + "n");
+
+        // Cancel the composition.
+        setComposingTextInBatch(input, "");
+
+        // Undo and redo do nothing.
+        mTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("flower", mTextView.getText().toString());
+        mTextView.onTextContextMenuItem(android.R.id.redo);
+        assertEquals("flower", mTextView.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testUndo_imeEmptyBatch() {
+        InputConnection input = initTextViewForSimulatedIme();
+        mTextView.setText("flower");
+
+        // Send an empty batch edit. This happens if the IME is hidden and shown.
+        input.beginBatchEdit();
+        input.endBatchEdit();
+
+        // Undo and redo do nothing.
+        mTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("flower", mTextView.getText().toString());
+        mTextView.onTextContextMenuItem(android.R.id.redo);
+        assertEquals("flower", mTextView.getText().toString());
+    }
+
+    public void testUndo_setText() {
+        initTextViewForTyping();
+
+        // Create two undo operations, an insert and a delete.
+        mInstrumentation.sendStringSync("xyz");
+        sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Calling setText() clears both undo operations, so undo doesn't happen.
+                mTextView.setText("Hello", BufferType.EDITABLE);
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("Hello", mTextView.getText().toString());
+
+                // Clearing text programmatically does not undo either.
+                mTextView.setText("", BufferType.EDITABLE);
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testRedo_setText() {
+        initTextViewForTyping();
+
+        // Type some text. This creates an undo entry.
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Undo the typing to create a redo entry.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+
+                // Calling setText() clears the redo stack, so redo doesn't happen.
+                mTextView.setText("Hello", BufferType.EDITABLE);
+                mTextView.onTextContextMenuItem(android.R.id.redo);
+                assertEquals("Hello", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_directAppend() {
+        initTextViewForTyping();
+
+        // Type some text.
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Programmatically append some text.
+                mTextView.append("def");
+                assertEquals("abcdef", mTextView.getText().toString());
+
+                // Undo removes the append as a separate step.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("abc", mTextView.getText().toString());
+
+                // Another undo removes the original typing.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_directInsert() {
+        initTextViewForTyping();
+
+        // Type some text.
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Directly modify the underlying Editable to insert some text.
+                // NOTE: This is a violation of the API of getText() which specifies that the
+                // returned object should not be modified. However, some apps do this anyway and
+                // the framework needs to handle it.
+                Editable text = (Editable) mTextView.getText();
+                text.insert(0, "def");
+                assertEquals("defabc", mTextView.getText().toString());
+
+                // Undo removes the insert as a separate step.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("abc", mTextView.getText().toString());
+
+                // Another undo removes the original typing.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_noCursor() {
+        initTextViewForTyping();
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Append some text to create an undo operation. There is no cursor present.
+                mTextView.append("cat");
+
+                // Place the cursor at the end of the text so the undo will have to change it.
+                Selection.setSelection((Spannable) mTextView.getText(), 3);
+
+                // Undo the append. This should not crash, despite not having a valid cursor
+                // position in the undo operation.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_textWatcher() {
+        initTextViewForTyping();
+
+        // Add a TextWatcher that converts the text to spaces on each change.
+        mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
+
+        // Type some text.
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // TextWatcher altered the text.
+                assertEquals("   ", mTextView.getText().toString());
+
+                // Undo reverses both changes in one step.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_textWatcherDirectAppend() {
+        initTextViewForTyping();
+
+        // Add a TextWatcher that converts the text to spaces on each change.
+        mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Programmatically append some text. The TextWatcher changes it to spaces.
+                mTextView.append("abc");
+                assertEquals("   ", mTextView.getText().toString());
+
+                // Undo reverses both changes in one step.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_shortcuts() {
+        initTextViewForTyping();
+
+        // Type some text.
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Pressing Control-Z triggers undo.
+                KeyEvent control = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z, 0,
+                        KeyEvent.META_CTRL_LEFT_ON);
+                assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, control));
+                assertEquals("", mTextView.getText().toString());
+
+                // Pressing Control-Shift-Z triggers redo.
+                KeyEvent controlShift = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z,
+                        0, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_SHIFT_LEFT_ON);
+                assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, controlShift));
+                assertEquals("abc", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_saveInstanceState() {
+        initTextViewForTyping();
+
+        // Type some text to create an undo operation.
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Parcel and unparcel the TextView.
+                Parcelable state = mTextView.onSaveInstanceState();
+                mTextView.onRestoreInstanceState(state);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Delete a character to create a new undo operation.
+        sendKeys(KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                assertEquals("ab", mTextView.getText().toString());
+
+                // Undo the delete.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("abc", mTextView.getText().toString());
+
+                // Undo the typing, which verifies that the original undo operation was parceled
+                // correctly.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+
+                // Parcel and unparcel the undo stack (which is empty but has been used and may
+                // contain other state).
+                Parcelable state = mTextView.onSaveInstanceState();
+                mTextView.onRestoreInstanceState(state);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testUndo_saveInstanceStateEmpty() {
+        initTextViewForTyping();
+
+        // Type and delete to create two new undo operations.
+        mInstrumentation.sendStringSync("a");
+        sendKeys(KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Empty the undo stack then parcel and unparcel the TextView. While the undo
+                // stack contains no operations it may contain other state.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                Parcelable state = mTextView.onSaveInstanceState();
+                mTextView.onRestoreInstanceState(state);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Create two more undo operations.
+        mInstrumentation.sendStringSync("b");
+        sendKeys(KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Verify undo still works.
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("b", mTextView.getText().toString());
+                mTextView.onTextContextMenuItem(android.R.id.undo);
+                assertEquals("", mTextView.getText().toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
     @UiThreadTest
     public void testSetText() {
         TextView tv = findTextView(R.id.textview_text);
@@ -1583,17 +2009,7 @@
     }
 
     public void testPressKey() {
-        final QwertyKeyListener qwertyKeyListener
-                = QwertyKeyListener.getInstance(false, Capitalize.NONE);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-                mTextView.setKeyListener(qwertyKeyListener);
-                mTextView.setText("", BufferType.EDITABLE);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        initTextViewForTyping();
 
         mInstrumentation.sendStringSync("a");
         assertEquals("a", mTextView.getText().toString());
@@ -3005,6 +3421,39 @@
         assertTrue(mTextView.didTouchFocusSelect());
     }
 
+    public void testSelectAllJustAfterTap() {
+        // Prepare an EditText with focus.
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView = new EditText(mActivity);
+                mActivity.setContentView(mTextView);
+
+                assertFalse(mTextView.didTouchFocusSelect());
+                mTextView.setFocusable(true);
+                mTextView.requestFocus();
+                assertTrue(mTextView.didTouchFocusSelect());
+
+                mTextView.setText("Hello, World.", BufferType.SPANNABLE);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Tap the view to show InsertPointController.
+        TouchUtils.tapView(this, mTextView);
+
+        // Execute SelectAll context menu.
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView.onTextContextMenuItem(android.R.id.selectAll);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // The selection must be whole of the text contents.
+        assertEquals(0, mTextView.getSelectionStart());
+        assertEquals(mTextView.length(), mTextView.getSelectionEnd());
+    }
+
     public void testExtractText() {
         mTextView = new TextView(mActivity);
 
@@ -3200,6 +3649,26 @@
         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
     }
 
+    public void testAllCapsLocalization() {
+        String testString = "abcdefghijklmnopqrstuvwxyz";
+
+        // The capitalized characters of "i" on Turkish and Azerbaijani are different from English.
+        Locale[] testLocales = {
+            new Locale("az", "AZ"),
+            new Locale("tr", "TR"),
+            new Locale("en", "US"),
+        };
+
+        TextView tv = new TextView(mActivity);
+        tv.setAllCaps(true);
+        for (Locale locale: testLocales) {
+            tv.setTextLocale(locale);
+            assertEquals("Locale: " + locale.getDisplayName(),
+                         testString.toUpperCase(locale),
+                         tv.getTransformationMethod().getTransformation(testString, tv).toString());
+        }
+    }
+
     @UiThreadTest
     public void testTextAlignmentDefault() {
         TextView tv = new TextView(getActivity());
@@ -3925,4 +4394,35 @@
             }
         }
     }
+
+    /**
+     * A TextWatcher that converts the text to spaces whenever the text changes.
+     */
+    private static class ConvertToSpacesTextWatcher implements TextWatcher {
+        boolean mChangingText;
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            // Avoid infinite recursion.
+            if (mChangingText) {
+                return;
+            }
+            mChangingText = true;
+            // Create a string of s.length() spaces.
+            StringBuilder builder = new StringBuilder(s.length());
+            for (int i = 0; i < s.length(); i++) {
+                builder.append(' ');
+            }
+            s.replace(0, s.length(), builder.toString());
+            mChangingText = false;
+        }
+    }
 }
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk b/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
index 90bdb61..3827754 100644
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
+++ b/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_DEX_PREOPT := false
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tools/Android.mk b/tools/Android.mk
index 0a05aed..b784393 100644
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -12,4 +12,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Build the CTS harness
+
+JUNIT_HOST_JAR := $(HOST_OUT_JAVA_LIBRARIES)/junit.jar
+HOSTTESTLIB_JAR := $(HOST_OUT_JAVA_LIBRARIES)/hosttestlib.jar
+TF_JAR := $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
+CTS_TF_JAR := $(HOST_OUT_JAVA_LIBRARIES)/cts-tradefed.jar
+CTS_TF_EXEC_PATH ?= $(HOST_OUT_EXECUTABLES)/cts-tradefed
+
+cts_prebuilt_jar := $(HOST_OUT)/cts/android-cts/tools/cts-prebuilt.jar
+$(cts_prebuilt_jar): PRIVATE_TESTS_DIR := $(HOST_OUT)/cts/android-cts/repository/testcases
+$(cts_prebuilt_jar): PRIVATE_PLANS_DIR := $(HOST_OUT)/cts/android-cts/repository/plans
+$(cts_prebuilt_jar): PRIVATE_TOOLS_DIR := $(HOST_OUT)/cts/android-cts/tools
+$(cts_prebuilt_jar): $(JUNIT_HOST_JAR) $(HOSTTESTLIB_JAR) $(TF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(ADDITIONAL_TF_JARS) | $(ACP) $(HOST_OUT_EXECUTABLES)/adb
+	mkdir -p $(PRIVATE_TESTS_DIR)
+	mkdir -p $(PRIVATE_PLANS_DIR)
+	mkdir -p $(PRIVATE_TOOLS_DIR)
+	$(ACP) -fp $(JUNIT_HOST_JAR) $(HOSTTESTLIB_JAR) $(TF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(ADDITIONAL_TF_JARS) $(PRIVATE_TOOLS_DIR)
+
+.PHONY: cts-harness
+cts-harness : $(cts_prebuilt_jar)
+
 include $(call all-subdir-makefiles)
diff --git a/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java b/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
index 94761fb..fb6691d 100644
--- a/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
+++ b/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
@@ -89,6 +89,7 @@
         List<String> classPath = new ArrayList<String>();
         classPath.add("./prebuilts/misc/common/tradefed/tradefed-prebuilt.jar");
         classPath.add("./prebuilts/misc/common/ub-uiautomator/ub-uiautomator.jar");
+        classPath.add("./prebuilts/misc/common/ub-janktesthelper/ub-janktesthelper.jar");
         return join(classPath, ":");
     }
 
diff --git a/tools/device-setup/TestDeviceSetup/Android.mk b/tools/device-setup/TestDeviceSetup/Android.mk
index 44e66bb..02c20d4 100644
--- a/tools/device-setup/TestDeviceSetup/Android.mk
+++ b/tools/device-setup/TestDeviceSetup/Android.mk
@@ -29,7 +29,7 @@
 
 LOCAL_PACKAGE_NAME := TestDeviceSetup
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 # ======================================================
 # also build a static host library for the device info constants
diff --git a/tools/junit/Android.mk b/tools/junit/Android.mk
index b581149..90e6924 100644
--- a/tools/junit/Android.mk
+++ b/tools/junit/Android.mk
@@ -21,3 +21,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := junit4-target
 LOCAL_DEX_PREOPT := false
 include $(BUILD_JAVA_LIBRARY)
+
+cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+	$(copy-file-to-target)
diff --git a/tools/tradefed-host/res/config/common-config.xml b/tools/tradefed-host/res/config/common-config.xml
new file mode 100644
index 0000000..e1ac66d
--- /dev/null
+++ b/tools/tradefed-host/res/config/common-config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Common base configuration for CTS module">
+    <!--
+      This common base configuration contains some commonly used preparers
+      -->
+    <target_preparer class="com.android.cts.tradefed.targetprep.CtsFilePusher">
+        <option name="cleanup" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.cts.tradefed.targetprep.CtsApkInstaller">
+        <option name="cleanup-apks" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer" />
+</configuration>
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index cc0e63a..2ee649d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
     @Option(name="cts-install-path", description="the path to the cts installation to use")
     private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
 
-    public static final String CTS_BUILD_VERSION = "5.1_r0.95";
+    public static final String CTS_BUILD_VERSION = "5.0_r1.91";
 
     /**
      * {@inheritDoc}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
index 903ac74..733eb4f 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
@@ -59,6 +59,7 @@
         File apkFile = new File(testApkDir, String.format("%s.apk", APK_NAME));
         if (!apkFile.exists()) {
             Log.e(LOG_TAG, String.format("Could not find %s", apkFile.getAbsolutePath()));
+            return;
         }
         // collect the instrumentation bundle results using instrumentation test
         // should work even though no tests will actually be run
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsApkInstaller.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsApkInstaller.java
new file mode 100644
index 0000000..08061b1
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsApkInstaller.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.tradefed.targetprep;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.targetprep.TestAppInstallSetup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Installs specified apks from CTS test case repository
+ */
+@OptionClass(alias="cts-apk-installer")
+public class CtsApkInstaller extends TestAppInstallSetup {
+
+    private CtsBuildHelper mBuildHelper = null;
+
+    protected CtsBuildHelper getCtsBuildHelper(IBuildInfo buildInfo) {
+        if (mBuildHelper == null) {
+            mBuildHelper = CtsBuildHelper.createBuildHelper(buildInfo);
+        }
+        return mBuildHelper;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected File getLocalPathForFilename(IBuildInfo buildInfo, String apkFileName)
+            throws TargetSetupError {
+        try {
+            return getCtsBuildHelper(buildInfo).getTestApp(apkFileName);
+        } catch (FileNotFoundException e) {
+            throw new TargetSetupError(String.format("apk not found: %s", apkFileName), e);
+        }
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsFilePusher.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsFilePusher.java
new file mode 100644
index 0000000..c6ae2e1
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsFilePusher.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.tradefed.targetprep;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.targetprep.PushFilePreparer;
+
+import java.io.File;
+
+/**
+ * Pushes specified testing artifacts from CTS test case repository
+ */
+@OptionClass(alias="cts-file-pusher")
+public class CtsFilePusher extends PushFilePreparer {
+
+    private CtsBuildHelper mBuildHelper;
+
+    protected CtsBuildHelper getCtsBuildHelper(IBuildInfo buildInfo) {
+        if (mBuildHelper == null) {
+            mBuildHelper = CtsBuildHelper.createBuildHelper(buildInfo);
+        }
+        return mBuildHelper;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
+        return new File(getCtsBuildHelper(buildInfo).getTestCasesDir(), fileName);
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityServiceTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityServiceTestRunner.java
deleted file mode 100644
index eafd608..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityServiceTestRunner.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.tradefed.testtype;
-
-import com.android.cts.util.AbiUtils;
-import com.android.ddmlib.Log;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.util.FileUtil;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-
-/**
- * Running the accessibility tests requires modification of secure
- * settings. Secure settings cannot be changed from device CTS tests
- * since system signature permission is required. Such settings can
- * be modified by the shell user, so a host side test is used for
- * installing a package with a delegating accessibility service, enabling
- * this service, running these tests, disabling the service, and removing
- * the delegating accessibility service package.
- *
- * @deprecated This class is not required in current CTS builds. Still
- * maintained so cts-tradefed can run against older CTS builds that still
- * require this class.
- */
-@Deprecated
-public class AccessibilityServiceTestRunner extends CtsInstrumentationApkTest {
-
-    private static final String LOG_TAG = AccessibilityServiceTestRunner.class.getSimpleName();
-
-    private static final String DELEGATING_ACCESSIBLITY_SERVICE_PACKAGE_NAME =
-        "android.accessibilityservice.delegate";
-
-    private static final String DELEGATING_ACCESSIBLITY_SERVICE_NAME =
-        "android.accessibilityservice.delegate.DelegatingAccessibilityService";
-
-    private static final String DELEGATING_ACCESSIBLITY_SERVICE_APK =
-        "CtsDelegatingAccessibilityService.apk";
-
-    @Override
-    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
-        beforeTest();
-        super.run(listener);
-        afterTest();
-    }
-
-    private void beforeTest() throws DeviceNotAvailableException {
-        installApkAndAssert(DELEGATING_ACCESSIBLITY_SERVICE_APK);
-        enableAccessibilityAndDelegatingService();
-    }
-
-    private void afterTest() throws DeviceNotAvailableException {
-        AccessibilityTestRunner.disableAccessibilityAndServices(getDevice());
-        uninstallAndAssert(DELEGATING_ACCESSIBLITY_SERVICE_PACKAGE_NAME);
-    }
-
-    private void installApkAndAssert(String apkName) throws DeviceNotAvailableException {
-        File file = FileUtil.getFileForPath(mCtsBuild.getTestCasesDir(), apkName);
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        String errorMessage = getDevice().installPackage(file, true, options);
-        TestCase.assertNull("Error installing: " + apkName, errorMessage);
-    }
-
-    private void uninstallAndAssert(String packageName) throws DeviceNotAvailableException {
-        String errorMessage = getDevice().uninstallPackage(packageName);
-        TestCase.assertNull("Error uninstalling: " + packageName, errorMessage);
-    }
-
-    private void enableAccessibilityAndDelegatingService() throws DeviceNotAvailableException {
-        String componentName = DELEGATING_ACCESSIBLITY_SERVICE_PACKAGE_NAME + "/"
-            + DELEGATING_ACCESSIBLITY_SERVICE_NAME;
-        AccessibilityTestRunner.enableAccessibilityAndServices(getDevice(),
-                componentName);
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityTestRunner.java
deleted file mode 100644
index 9ba4109..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityTestRunner.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.tradefed.testtype;
-
-import com.android.cts.tradefed.targetprep.SettingsToggler;
-import com.android.cts.util.AbiUtils;
-import com.android.ddmlib.Log;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.util.FileUtil;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-
-/**
- * Running the accessibility tests requires modification of secure
- * settings. Secure settings cannot be changed from device CTS tests
- * since system signature permission is required. Such settings can
- * be modified by the shell user, so a host side test is used for
- * installing a package with some accessibility services, enabling
- * these services, running the tests, disabling the services, and removing
- * the accessibility services package.
- */
-public class AccessibilityTestRunner extends CtsInstrumentationApkTest {
-
-    private static final String LOG_TAG = AccessibilityTestRunner.class.getSimpleName();
-
-    private static final String SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME =
-        "android.view.accessibility.services";
-
-    private static final String SPEAKING_ACCESSIBLITY_SERVICE_NAME =
-        "android.view.accessibility.services.SpeakingAccessibilityService";
-
-    private static final String VIBRATING_ACCESSIBLITY_SERVICE_NAME =
-        "android.view.accessibility.services.VibratingAccessibilityService";
-
-    private static final String SOME_ACCESSIBLITY_SERVICES_APK =
-        "CtsSomeAccessibilityServices.apk";
-
-    @Override
-    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
-        beforeTest();
-        super.run(listener);
-        afterTest();
-    }
-
-    private void beforeTest() throws DeviceNotAvailableException {
-        installApkAndAssert(SOME_ACCESSIBLITY_SERVICES_APK);
-        enableAccessibilityAndServices();
-    }
-
-    private void afterTest() throws DeviceNotAvailableException {
-        disableAccessibilityAndServices(getDevice());
-        uninstallAndAssert(SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME);
-    }
-
-    private void installApkAndAssert(String apkName) throws DeviceNotAvailableException {
-        File file = FileUtil.getFileForPath(mCtsBuild.getTestCasesDir(), apkName);
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        String errorMessage = getDevice().installPackage(file, true, options);
-        TestCase.assertNull("Error installing: " + apkName, errorMessage);
-    }
-
-    private void uninstallAndAssert(String packageName) throws DeviceNotAvailableException {
-        String errorMessage = getDevice().uninstallPackage(packageName);
-        TestCase.assertNull("Error uninstalling: " + packageName, errorMessage);
-    }
-
-    private void enableAccessibilityAndServices() throws DeviceNotAvailableException {
-        String enabledServicesValue =
-              SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME + "/" + SPEAKING_ACCESSIBLITY_SERVICE_NAME
-            + ":"
-            + SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME + "/" + VIBRATING_ACCESSIBLITY_SERVICE_NAME;
-        enableAccessibilityAndServices(getDevice(), enabledServicesValue);
-    }
-
-    static void enableAccessibilityAndServices(ITestDevice device, String value)
-            throws DeviceNotAvailableException {
-        SettingsToggler.setSecureString(device, "enabled_accessibility_services", value);
-        SettingsToggler.setSecureString(device,
-                "touch_exploration_granted_accessibility_services", value);
-        SettingsToggler.setSecureInt(device, "accessibility_enabled", 1);
-    }
-
-    static void disableAccessibilityAndServices(ITestDevice device)
-            throws DeviceNotAvailableException {
-        SettingsToggler.updateSecureString(device, "enabled_accessibility_services", "");
-        SettingsToggler.updateSecureString(device,
-                "touch_exploration_granted_accessibility_services", "");
-        SettingsToggler.updateSecureInt(device, "accessibility_enabled", 0);
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index c2c2a10..b3bc7da 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -37,12 +37,18 @@
 import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.result.ResultForwarder;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
 import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IDeviceTest;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IResumableTest;
 import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.testtype.InstrumentationTest;
 import com.android.tradefed.util.AbiFormatter;
 import com.android.tradefed.util.RunUtil;
 import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
@@ -63,6 +69,7 @@
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -82,6 +89,8 @@
     private static final String TEST_OPTION = "test";
     public static final String CONTINUE_OPTION = "continue-session";
     public static final String RUN_KNOWN_FAILURES_OPTION = "run-known-failures";
+    private static final String INCLUDE_FILTERS_OPTION = "include";
+    private static final String EXCLUDE_FILTERS_OPTION = "exclude";
 
     public static final String PACKAGE_NAME_METRIC = "packageName";
     public static final String PACKAGE_ABI_METRIC = "packageAbi";
@@ -180,9 +189,14 @@
             "Collect dEQP logs from the device.")
     private boolean mCollectDeqpLogs = false;
 
+    @Option(name = INCLUDE_FILTERS_OPTION, description = "Positive filters to pass to tests.")
+    private List<String> mPositiveFilters = new ArrayList<> ();
+
+    @Option(name = EXCLUDE_FILTERS_OPTION, description = "Negative filters to pass to tests.")
+    private List<String> mNegativeFilters = new ArrayList<> ();
+
     @Option(name = "min-pre-reboot-package-count", description =
             "The minimum number of packages to require a pre test reboot")
-
     private int mMinPreRebootPackageCount = 2;
     private final int mShardAssignment;
     private final int mTotalShards;
@@ -525,9 +539,33 @@
                 if (test instanceof DeqpTestRunner) {
                     ((DeqpTestRunner)test).setCollectLogs(mCollectDeqpLogs);
                 }
+                if (test instanceof GeeTest) {
+                    if (!mPositiveFilters.isEmpty()) {
+                        String positivePatterns = join(mPositiveFilters, ":");
+                        ((GeeTest)test).setPositiveFilters(positivePatterns);
+                    }
+                    if (!mNegativeFilters.isEmpty()) {
+                        String negativePatterns = join(mNegativeFilters, ":");
+                        ((GeeTest)test).setPositiveFilters(negativePatterns);
+                    }
+                }
+                if (test instanceof InstrumentationTest) {
+                    if (!mPositiveFilters.isEmpty()) {
+                        String annotation = join(mPositiveFilters, ",");
+                        ((InstrumentationTest)test).addInstrumentationArg(
+                                "annotation", annotation);
+                    }
+                    if (!mNegativeFilters.isEmpty()) {
+                        String notAnnotation = join(mNegativeFilters, ",");
+                        ((InstrumentationTest)test).addInstrumentationArg(
+                                "notAnnotation", notAnnotation);
+                    }
+                }
 
                 forwardPackageDetails(testPackage.getPackageDef(), listener);
+                performPackagePrepareSetup(testPackage.getPackageDef());
                 test.run(filterMap.get(testPackage.getPackageDef().getId()));
+                performPackagePreparerTearDown(testPackage.getPackageDef());
                 if (i < mTestPackageList.size() - 1) {
                     TestPackage nextPackage = mTestPackageList.get(i + 1);
                     rebootIfNecessary(testPackage, nextPackage);
@@ -562,6 +600,79 @@
     }
 
     /**
+     * Invokes {@link ITargetPreparer}s configured for the test package. {@link TargetSetupError}s
+     * thrown by any preparer will be rethrown as {@link RuntimeException} so that the entire test
+     * package will be skipped for execution. Note that preparers will be invoked in the same order
+     * as they are defined in the module test config.
+     * @param packageDef definition for the test package
+     * @throws DeviceNotAvailableException
+     */
+    private void performPackagePrepareSetup(ITestPackageDef packageDef)
+            throws DeviceNotAvailableException {
+        List<ITargetPreparer> preparers = packageDef.getPackagePreparers();
+        if (preparers != null) {
+            for (ITargetPreparer preparer : preparers) {
+                if (preparer instanceof IAbiReceiver) {
+                    ((IAbiReceiver) preparer).setAbi(packageDef.getAbi());
+                }
+                try {
+                    preparer.setUp(getDevice(), mBuildInfo);
+                } catch (BuildError e) {
+                    // This should only happen for flashing new build
+                    CLog.e("Unexpected BuildError from preparer: %s",
+                        preparer.getClass().getCanonicalName());
+                } catch (TargetSetupError e) {
+                    // log preparer class then rethrow & let caller handle
+                    CLog.e("TargetSetupError in preparer: %s",
+                        preparer.getClass().getCanonicalName());
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Invokes clean up step for {@link ITargetCleaner}s configured for the test package. Note that
+     * the cleaners will be invoked in the reverse order as they are defined in module test config.
+     * @param packageDef definition for the test package
+     * @throws DeviceNotAvailableException
+     */
+    private void performPackagePreparerTearDown(ITestPackageDef packageDef)
+            throws DeviceNotAvailableException {
+        List<ITargetPreparer> preparers = packageDef.getPackagePreparers();
+        if (preparers != null) {
+            ListIterator<ITargetPreparer> itr = preparers.listIterator(preparers.size());
+            // do teardown in reverse order
+            while (itr.hasPrevious()) {
+                ITargetPreparer preparer = itr.previous();
+                if (preparer instanceof ITargetCleaner) {
+                    ((ITargetCleaner) preparer).tearDown(getDevice(), mBuildInfo, null);
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method to join strings. Exposed for unit tests
+     * @param input
+     * @param conjunction
+     * @return string with elements of the input list with interleaved conjunction.
+     */
+    protected static String join(List<String> input, String conjunction) {
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for (String item : input) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(conjunction);
+            }
+            sb.append(item);
+        }
+        return sb.toString();
+    }
+
+    /**
      * @param allTestPackageDefList The package list to filter
      * @param deviceAbiSet The ABIs supported by the device being tested
      * @return A {@link List} of {@link ITestPackageDef}s that should be tested
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
index 8eb1621..55173fc 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
@@ -22,8 +22,14 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Test runner for dEQP tests
@@ -35,29 +41,35 @@
     private static final String DEQP_ONDEVICE_APK = "com.drawelements.deqp.apk";
     private static final String DEQP_ONDEVICE_PKG = "com.drawelements.deqp";
     private static final String INCOMPLETE_LOG_MESSAGE = "Crash: Incomplete test log";
+    private static final String DEVICE_LOST_MESSAGE = "Crash: Device lost";
+    private static final String SKIPPED_INSTANCE_LOG_MESSAGE = "Configuration skipped";
+    private static final String CASE_LIST_FILE_NAME = "/sdcard/dEQP-TestCaseList.txt";
+    private static final String LOG_FILE_NAME = "/sdcard/TestLog.qpa";
+    public static final String FEATURE_LANDSCAPE = "android.hardware.screen.landscape";
+    public static final String FEATURE_PORTRAIT = "android.hardware.screen.portrait";
 
-    private final int TESTCASE_BATCH_LIMIT = 1000;
-
-    private boolean mLogData;
-
-    private ITestDevice mDevice;
+    private static final int TESTCASE_BATCH_LIMIT = 1000;
+    private static final BatchRunConfiguration DEFAULT_CONFIG =
+        new BatchRunConfiguration("rgba8888d24s8", "unspecified", "window");
 
     private final String mPackageName;
     private final String mName;
-    private Collection<TestIdentifier> mTests;
+    private final Collection<TestIdentifier> mRemainingTests;
+    private final Map<TestIdentifier, Set<BatchRunConfiguration>> mTestInstances;
+    private final TestInstanceResultListener mInstanceListerner;
     private IAbi mAbi;
     private CtsBuildHelper mCtsBuild;
+    private boolean mLogData;
+    private ITestDevice mDevice;
+    private Set<String> mDeviceFeatures;
 
-    private TestIdentifier mCurrentTestId;
-    private boolean mGotTestResult;
-    private String mCurrentTestLog;
-
-    private ITestInvocationListener mListener;
-
-    public DeqpTestRunner(String packageName, String name, Collection<TestIdentifier> tests) {
+    public DeqpTestRunner(String packageName, String name, Collection<TestIdentifier> tests,
+            Map<TestIdentifier, List<Map<String,String>>> testInstances) {
         mPackageName = packageName;
         mName = name;
-        mTests = tests;
+        mRemainingTests = new LinkedList<>(tests); // avoid modifying arguments
+        mTestInstances = parseTestInstances(tests, testInstances);
+        mInstanceListerner = new TestInstanceResultListener();
         mLogData = false;
     }
 
@@ -95,18 +107,390 @@
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    private static final class CapabilityQueryFailureException extends Exception {
+    };
+
+    /**
+     * Test configuration of dEPQ test instance execution.
+     * Exposed for unit testing
+     */
+    public static final class BatchRunConfiguration {
+        public static final String ROTATION_UNSPECIFIED = "unspecified";
+        public static final String ROTATION_PORTRAIT = "0";
+        public static final String ROTATION_LANDSCAPE = "90";
+        public static final String ROTATION_REVERSE_PORTRAIT = "180";
+        public static final String ROTATION_REVERSE_LANDSCAPE = "270";
+
+        private final String mGlConfig;
+        private final String mRotation;
+        private final String mSurfaceType;
+
+        public BatchRunConfiguration(String glConfig, String rotation, String surfaceType) {
+            mGlConfig = glConfig;
+            mRotation = rotation;
+            mSurfaceType = surfaceType;
+        }
+
+        /**
+         * Get string that uniquely identifies this config
+         */
+        public String getId() {
+            return String.format("{glformat=%s,rotation=%s,surfacetype=%s}",
+                    mGlConfig, mRotation, mSurfaceType);
+        }
+
+        /**
+         * Get the GL config used in this configuration.
+         */
+        public String getGlConfig() {
+            return mGlConfig;
+        }
+
+        /**
+         * Get the screen rotation used in this configuration.
+         */
+        public String getRotation() {
+            return mRotation;
+        }
+
+        /**
+         * Get the surface type used in this configuration.
+         */
+        public String getSurfaceType() {
+            return mSurfaceType;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other == null) {
+                return false;
+            } else if (!(other instanceof BatchRunConfiguration)) {
+                return false;
+            } else {
+                return getId().equals(((BatchRunConfiguration)other).getId());
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return getId().hashCode();
+        }
+    }
+
+    /**
+     * dEQP test instance listerer and invocation result forwarded
+     */
+    private class TestInstanceResultListener {
+        private ITestInvocationListener mSink;
+        private BatchRunConfiguration mRunConfig;
+
+        private TestIdentifier mCurrentTestId;
+        private boolean mGotTestResult;
+        private String mCurrentTestLog;
+
+        private class PendingResult
+        {
+            boolean allInstancesPassed;
+            Map<BatchRunConfiguration, String> testLogs;
+            Map<BatchRunConfiguration, String> errorMessages;
+            Set<BatchRunConfiguration> remainingConfigs;
+        };
+        private final Map<TestIdentifier, PendingResult> mPendingResults = new HashMap<>();
+
+        public void setSink(ITestInvocationListener sink) {
+            mSink = sink;
+        }
+
+        public void setCurrentConfig(BatchRunConfiguration runConfig) {
+            mRunConfig = runConfig;
+        }
+
+        /**
+         * Forward result to sink
+         */
+        private void forwardFinalizedPendingResult() {
+            if (mRemainingTests.contains(mCurrentTestId)) {
+                final PendingResult result = mPendingResults.get(mCurrentTestId);
+
+                mRemainingTests.remove(mCurrentTestId);
+                mSink.testStarted(mCurrentTestId);
+
+                // Test Log
+                if (mLogData) {
+                    for (Map.Entry<BatchRunConfiguration, String> entry :
+                            result.testLogs.entrySet()) {
+                        final ByteArrayInputStreamSource source
+                                = new ByteArrayInputStreamSource(entry.getValue().getBytes());
+
+                        mSink.testLog(mCurrentTestId.getClassName() + "."
+                                + mCurrentTestId.getTestName() + "@" + entry.getKey().getId(),
+                                LogDataType.XML, source);
+
+                        source.cancel();
+                    }
+                }
+
+                // Error message
+                if (!result.allInstancesPassed) {
+                    final StringBuilder errorLog = new StringBuilder();
+
+                    for (Map.Entry<BatchRunConfiguration, String> entry :
+                            result.errorMessages.entrySet()) {
+                        if (errorLog.length() > 0) {
+                            errorLog.append('\n');
+                        }
+                        errorLog.append(String.format("=== with config %s ===\n",
+                                entry.getKey().getId()));
+                        errorLog.append(entry.getValue());
+                    }
+
+                    mSink.testFailed(mCurrentTestId, errorLog.toString());
+                }
+
+                // Clear all that won't be used again. The memory usage of these might
+                // add up to quite large numbers
+                result.testLogs = null;
+                result.errorMessages = null;
+                final Map<String, String> emptyMap = Collections.emptyMap();
+                mSink.testEnded(mCurrentTestId, emptyMap);
+            }
+        }
+
+        /**
+         * Declare existence of a test and instances
+         */
+        public void setTestInstances(TestIdentifier testId, Set<BatchRunConfiguration> configs) {
+            // Test instances cannot change at runtime, ignore if we have already set this
+            if (!mPendingResults.containsKey(testId)) {
+                final PendingResult pendingResult = new PendingResult();
+                pendingResult.allInstancesPassed = true;
+                pendingResult.testLogs = new LinkedHashMap<>();
+                pendingResult.errorMessages = new LinkedHashMap<>();
+                pendingResult.remainingConfigs = new HashSet<>(configs); // avoid mutating argument
+                mPendingResults.put(testId, pendingResult);
+            }
+        }
+
+        /**
+         * Query if test instance has not yet been executed
+         */
+        public boolean isPendingTestInstance(TestIdentifier testId,
+                BatchRunConfiguration config) {
+            final PendingResult result = mPendingResults.get(testId);
+            return result.remainingConfigs.contains(config);
+        }
+
+        /**
+         * Fake execution of an instance with current config
+         */
+        public void skipTest(TestIdentifier testId) {
+            final PendingResult result = mPendingResults.get(testId);
+
+            result.errorMessages.put(mRunConfig, SKIPPED_INSTANCE_LOG_MESSAGE);
+            result.remainingConfigs.remove(mRunConfig);
+
+            if (result.remainingConfigs.isEmpty()) {
+                // fake as if we actually run the test
+                mCurrentTestId = testId;
+                forwardFinalizedPendingResult();
+                mCurrentTestId = null;
+            }
+        }
+
+        /**
+         * Handles beginning of dEQP session.
+         */
+        private void handleBeginSession(Map<String, String> values) {
+            // ignore
+        }
+
+        /**
+         * Handles end of dEQP session.
+         */
+        private void handleEndSession(Map<String, String> values) {
+            // ignore
+        }
+
+        /**
+         * Handles beginning of dEQP testcase.
+         */
+        private void handleBeginTestCase(Map<String, String> values) {
+            mCurrentTestId = pathToIdentifier(values.get("dEQP-BeginTestCase-TestCasePath"));
+            mCurrentTestLog = "";
+            mGotTestResult = false;
+
+            // mark instance as started
+            mPendingResults.get(mCurrentTestId).remainingConfigs.remove(mRunConfig);
+        }
+
+        /**
+         * Handles end of dEQP testcase.
+         */
+        private void handleEndTestCase(Map<String, String> values) {
+            final PendingResult result = mPendingResults.get(mCurrentTestId);
+            if (!mGotTestResult) {
+                result.allInstancesPassed = false;
+                result.errorMessages.put(mRunConfig, INCOMPLETE_LOG_MESSAGE);
+            }
+
+            if (mLogData && mCurrentTestLog != null && mCurrentTestLog.length() > 0) {
+                result.testLogs.put(mRunConfig, mCurrentTestLog);
+            }
+
+            // Pending result finished, report result
+            if (result.remainingConfigs.isEmpty()) {
+                forwardFinalizedPendingResult();
+            }
+            mCurrentTestId = null;
+        }
+
+        /**
+         * Handles dEQP testcase result.
+         */
+        private void handleTestCaseResult(Map<String, String> values) {
+            String code = values.get("dEQP-TestCaseResult-Code");
+            String details = values.get("dEQP-TestCaseResult-Details");
+
+            if (code.compareTo("Pass") == 0) {
+                mGotTestResult = true;
+            } else if (code.compareTo("NotSupported") == 0) {
+                mGotTestResult = true;
+            } else if (code.compareTo("QualityWarning") == 0) {
+                mGotTestResult = true;
+            } else if (code.compareTo("CompatibilityWarning") == 0) {
+                mGotTestResult = true;
+            } else if (code.compareTo("Fail") == 0 || code.compareTo("ResourceError") == 0
+                    || code.compareTo("InternalError") == 0 || code.compareTo("Crash") == 0
+                    || code.compareTo("Timeout") == 0) {
+                mPendingResults.get(mCurrentTestId).allInstancesPassed = false;
+                mPendingResults.get(mCurrentTestId)
+                        .errorMessages.put(mRunConfig, code + ": " + details);
+                mGotTestResult = true;
+            } else {
+                String codeError = "Unknown result code: " + code;
+                mPendingResults.get(mCurrentTestId).allInstancesPassed = false;
+                mPendingResults.get(mCurrentTestId)
+                        .errorMessages.put(mRunConfig, codeError + ": " + details);
+                mGotTestResult = true;
+            }
+        }
+
+        /**
+         * Handles terminated dEQP testcase.
+         */
+        private void handleTestCaseTerminate(Map<String, String> values) {
+            final PendingResult result = mPendingResults.get(mCurrentTestId);
+
+            String reason = values.get("dEQP-TerminateTestCase-Reason");
+            mPendingResults.get(mCurrentTestId).allInstancesPassed = false;
+            mPendingResults.get(mCurrentTestId)
+                    .errorMessages.put(mRunConfig, "Terminated: " + reason);
+
+            // Pending result finished, report result
+            if (result.remainingConfigs.isEmpty()) {
+                forwardFinalizedPendingResult();
+            }
+
+            mCurrentTestId = null;
+            mGotTestResult = true;
+        }
+
+        /**
+         * Handles dEQP testlog data.
+         */
+        private void handleTestLogData(Map<String, String> values) {
+            mCurrentTestLog = mCurrentTestLog + values.get("dEQP-TestLogData-Log");
+        }
+
+        /**
+         * Handles new instrumentation status message.
+         */
+        public void handleStatus(Map<String, String> values) {
+            String eventType = values.get("dEQP-EventType");
+
+            if (eventType == null) {
+                return;
+            }
+
+            if (eventType.compareTo("BeginSession") == 0) {
+                handleBeginSession(values);
+            } else if (eventType.compareTo("EndSession") == 0) {
+                handleEndSession(values);
+            } else if (eventType.compareTo("BeginTestCase") == 0) {
+                handleBeginTestCase(values);
+            } else if (eventType.compareTo("EndTestCase") == 0) {
+                handleEndTestCase(values);
+            } else if (eventType.compareTo("TestCaseResult") == 0) {
+                handleTestCaseResult(values);
+            } else if (eventType.compareTo("TerminateTestCase") == 0) {
+                handleTestCaseTerminate(values);
+            } else if (eventType.compareTo("TestLogData") == 0) {
+                handleTestLogData(values);
+            }
+        }
+
+        /**
+         * Signal listener that batch ended to flush incomplete results.
+         */
+        public void endBatch() {
+            // end open test if when stream ends
+            if (mCurrentTestId != null) {
+                final Map<String, String> emptyMap = Collections.emptyMap();
+                handleEndTestCase(emptyMap);
+            }
+        }
+
+        /**
+         * Signal listener that device just died.
+         */
+        public void onDeviceLost() {
+            if (mCurrentTestId != null) {
+                final PendingResult result = mPendingResults.get(mCurrentTestId);
+
+                // kill current test
+                result.allInstancesPassed = false;
+                result.errorMessages.put(mRunConfig, DEVICE_LOST_MESSAGE);
+
+                if (mLogData && mCurrentTestLog != null && mCurrentTestLog.length() > 0) {
+                    result.testLogs.put(mRunConfig, mCurrentTestLog);
+                }
+
+                // finish all pending instances
+                result.remainingConfigs.clear();
+                forwardFinalizedPendingResult();
+                mCurrentTestId = null;
+            }
+        }
+    }
+
+    /**
      * dEQP instrumentation parser
      */
-    class InstrumentationParser extends MultiLineReceiver {
-        private DeqpTestRunner mDeqpTests;
+    private static class InstrumentationParser extends MultiLineReceiver {
+        private TestInstanceResultListener mListener;
 
         private Map<String, String> mValues;
         private String mCurrentName;
         private String mCurrentValue;
 
 
-        public InstrumentationParser(DeqpTestRunner tests) {
-            mDeqpTests = tests;
+        public InstrumentationParser(TestInstanceResultListener listener) {
+            mListener = listener;
         }
 
         /**
@@ -125,7 +509,7 @@
                         mCurrentValue = null;
                     }
 
-                    mDeqpTests.handleStatus(mValues);
+                    mListener.handleStatus(mValues);
                     mValues = null;
                 } else if (line.startsWith("INSTRUMENTATION_STATUS: dEQP-")) {
                     if (mCurrentName != null) {
@@ -161,7 +545,7 @@
             }
 
             if (mValues != null) {
-                mDeqpTests.handleStatus(mValues);
+                mListener.handleStatus(mValues);
                 mValues = null;
             }
         }
@@ -176,9 +560,112 @@
     }
 
     /**
+     * dEQP platfom query instrumentation parser
+     */
+    private static class PlatformQueryInstrumentationParser extends MultiLineReceiver {
+        private Map<String,String> mResultMap = new LinkedHashMap<>();
+        private int mResultCode;
+        private boolean mGotExitValue = false;
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void processNewLines(String[] lines) {
+            for (String line : lines) {
+                if (line.startsWith("INSTRUMENTATION_RESULT: ")) {
+                    final String parts[] = line.substring(24).split("=",2);
+                    if (parts.length == 2) {
+                        mResultMap.put(parts[0], parts[1]);
+                    } else {
+                        CLog.w("Instrumentation status format unexpected");
+                    }
+                } else if (line.startsWith("INSTRUMENTATION_CODE: ")) {
+                    try {
+                        mResultCode = Integer.parseInt(line.substring(22));
+                        mGotExitValue = true;
+                    } catch (NumberFormatException ex) {
+                        CLog.w("Instrumentation code format unexpected");
+                    }
+                }
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isCancelled() {
+            return false;
+        }
+
+        public boolean wasSuccessful() {
+            return mGotExitValue;
+        }
+
+        public int getResultCode() {
+            return mResultCode;
+        }
+
+        public Map<String,String> getResultMap() {
+            return mResultMap;
+        }
+    }
+
+    /**
+     * Parse map of instance arguments to map of BatchRunConfigurations
+     */
+    private static Map<TestIdentifier, Set<BatchRunConfiguration>> parseTestInstances(
+            Collection<TestIdentifier> tests,
+            Map<TestIdentifier, List<Map<String,String>>> testInstances) {
+        final Map<TestIdentifier, Set<BatchRunConfiguration>> instances = new HashMap<>();
+        for (final TestIdentifier test : tests) {
+            final Set<BatchRunConfiguration> testInstanceSet = new LinkedHashSet<>();
+            if (testInstances.get(test).isEmpty()) {
+                // no instances defined, use default
+                testInstanceSet.add(DEFAULT_CONFIG);
+            } else {
+                for (Map<String, String> instanceArgs : testInstances.get(test)) {
+                    testInstanceSet.add(parseRunConfig(instanceArgs));
+                }
+            }
+            instances.put(test, testInstanceSet);
+        }
+        return instances;
+    }
+
+    private static BatchRunConfiguration parseRunConfig(Map<String,String> instanceArguments) {
+        final String glConfig;
+        final String rotation;
+        final String surfaceType;
+
+        if (instanceArguments.containsKey("glconfig")) {
+            glConfig = instanceArguments.get("glconfig");
+        } else {
+            glConfig = DEFAULT_CONFIG.getGlConfig();
+        }
+        if (instanceArguments.containsKey("rotation")) {
+            rotation = instanceArguments.get("rotation");
+        } else {
+            rotation = DEFAULT_CONFIG.getRotation();
+        }
+        if (instanceArguments.containsKey("surfaceType")) {
+            surfaceType = instanceArguments.get("surfaceType");
+        } else {
+            surfaceType = DEFAULT_CONFIG.getSurfaceType();
+        }
+
+        return new BatchRunConfiguration(glConfig, rotation, surfaceType);
+    }
+
+    private Set<BatchRunConfiguration> getTestRunConfigs (TestIdentifier testId) {
+        return mTestInstances.get(testId);
+    }
+
+    /**
      * Converts dEQP testcase path to TestIdentifier.
      */
-    private TestIdentifier pathToIdentifier(String testPath) {
+    private static TestIdentifier pathToIdentifier(String testPath) {
         String[] components = testPath.split("\\.");
         String name = components[components.length - 1];
         String className = null;
@@ -194,150 +681,14 @@
         return new TestIdentifier(className, name);
     }
 
-    /**
-     * Handles beginning of dEQP session.
-     */
-    private void handleBeginSession(Map<String, String> values) {
-        String id = AbiUtils.createId(mAbi.getName(), mPackageName);
-        mListener.testRunStarted(id, mTests.size());
-    }
-
-    /**
-     * Handles end of dEQP session.
-     */
-    private void handleEndSession(Map<String, String> values) {
-        Map <String, String> emptyMap = Collections.emptyMap();
-        mListener.testRunEnded(0, emptyMap);
-    }
-
-    /**
-     * Handles beginning of dEQP testcase.
-     */
-    private void handleBeginTestCase(Map<String, String> values) {
-        mCurrentTestId = pathToIdentifier(values.get("dEQP-BeginTestCase-TestCasePath"));
-        mCurrentTestLog = "";
-        mGotTestResult = false;
-
-        mListener.testStarted(mCurrentTestId);
-        mTests.remove(mCurrentTestId);
-    }
-
-    /**
-     * Handles end of dEQP testcase.
-     */
-    private void handleEndTestCase(Map<String, String> values) {
-        Map <String, String> emptyMap = Collections.emptyMap();
-
-        if (!mGotTestResult) {
-            mListener.testFailed(mCurrentTestId,
-                    INCOMPLETE_LOG_MESSAGE);
-        }
-
-        if (mLogData && mCurrentTestLog != null && mCurrentTestLog.length() > 0) {
-            ByteArrayInputStreamSource source
-                    = new ByteArrayInputStreamSource(mCurrentTestLog.getBytes());
-
-            mListener.testLog(mCurrentTestId.getClassName() + "."
-                    + mCurrentTestId.getTestName(), LogDataType.XML, source);
-
-            source.cancel();
-        }
-
-        mListener.testEnded(mCurrentTestId, emptyMap);
-        mCurrentTestId = null;
-    }
-
-    /**
-     * Handles dEQP testcase result.
-     */
-    private void handleTestCaseResult(Map<String, String> values) {
-        String code = values.get("dEQP-TestCaseResult-Code");
-        String details = values.get("dEQP-TestCaseResult-Details");
-
-        if (code.compareTo("Pass") == 0) {
-            mGotTestResult = true;
-        } else if (code.compareTo("NotSupported") == 0) {
-            mGotTestResult = true;
-        } else if (code.compareTo("QualityWarning") == 0) {
-            mGotTestResult = true;
-        } else if (code.compareTo("CompatibilityWarning") == 0) {
-            mGotTestResult = true;
-        } else if (code.compareTo("Fail") == 0 || code.compareTo("ResourceError") == 0
-                || code.compareTo("InternalError") == 0 || code.compareTo("Crash") == 0
-                || code.compareTo("Timeout") == 0) {
-            mListener.testFailed(mCurrentTestId,
-                    code + ": " + details);
-            mGotTestResult = true;
-        } else {
-            mListener.testFailed(mCurrentTestId,
-                    "Unknown result code: " + code + ": " + details);
-            mGotTestResult = true;
-        }
-    }
-
-    /**
-     * Handles terminated dEQP testcase.
-     */
-    private void handleTestCaseTerminate(Map<String, String> values) {
-        Map <String, String> emptyMap = Collections.emptyMap();
-
-        String reason = values.get("dEQP-TerminateTestCase-Reason");
-        mListener.testFailed(mCurrentTestId,
-                "Terminated: " + reason);
-        mListener.testEnded(mCurrentTestId, emptyMap);
-
-        if (mLogData && mCurrentTestLog != null && mCurrentTestLog.length() > 0) {
-            ByteArrayInputStreamSource source
-                    = new ByteArrayInputStreamSource(mCurrentTestLog.getBytes());
-
-            mListener.testLog(mCurrentTestId.getClassName() + "."
-                    + mCurrentTestId.getTestName(), LogDataType.XML, source);
-
-            source.cancel();
-        }
-
-        mCurrentTestId = null;
-        mGotTestResult = true;
-    }
-
-    /**
-     * Handles dEQP testlog data.
-     */
-    private void handleTestLogData(Map<String, String> values) {
-        mCurrentTestLog = mCurrentTestLog + values.get("dEQP-TestLogData-Log");
-    }
-
-    /**
-     * Handles new instrumentation status message.
-     */
-    public void handleStatus(Map<String, String> values) {
-        String eventType = values.get("dEQP-EventType");
-
-        if (eventType == null) {
-            return;
-        }
-
-        if (eventType.compareTo("BeginSession") == 0) {
-            handleBeginSession(values);
-        } else if (eventType.compareTo("EndSession") == 0) {
-            handleEndSession(values);
-        } else if (eventType.compareTo("BeginTestCase") == 0) {
-            handleBeginTestCase(values);
-        } else if (eventType.compareTo("EndTestCase") == 0) {
-            handleEndTestCase(values);
-        } else if (eventType.compareTo("TestCaseResult") == 0) {
-            handleTestCaseResult(values);
-        } else if (eventType.compareTo("TerminateTestCase") == 0) {
-            handleTestCaseTerminate(values);
-        } else if (eventType.compareTo("TestLogData") == 0) {
-            handleTestLogData(values);
-        }
+    private String getId() {
+        return AbiUtils.createId(mAbi.getName(), mPackageName);
     }
 
     /**
      * Generates tescase trie from dEQP testcase paths. Used to define which testcases to execute.
      */
-    private String generateTestCaseTrieFromPaths(Collection<String> tests) {
+    private static String generateTestCaseTrieFromPaths(Collection<String> tests) {
         String result = "{";
         boolean first = true;
 
@@ -390,15 +741,11 @@
     /**
      * Generates testcase trie from TestIdentifiers.
      */
-    private String generateTestCaseTrie(Collection<TestIdentifier> tests) {
+    private static String generateTestCaseTrie(Collection<TestIdentifier> tests) {
         ArrayList<String> testPaths = new ArrayList<String>();
 
         for (TestIdentifier test : tests) {
             testPaths.add(test.getClassName() + "." + test.getTestName());
-
-            // Limit number of testcases for each run
-            if (testPaths.size() > TESTCASE_BATCH_LIMIT)
-                break;
         }
 
         return generateTestCaseTrieFromPaths(testPaths);
@@ -407,34 +754,183 @@
     /**
      * Executes tests on the device.
      */
-    private void executeTests(ITestInvocationListener listener) throws DeviceNotAvailableException {
-        InstrumentationParser parser = new InstrumentationParser(this);
-        String caseListFileName = "/sdcard/dEQP-TestCaseList.txt";
-        String logFileName = "/sdcard/TestLog.qpa";
-        String testCases = generateTestCaseTrie(mTests);
+    private void runTests() throws DeviceNotAvailableException, CapabilityQueryFailureException {
+        while (!mRemainingTests.isEmpty()) {
+            // select tests for the batch
+            final ArrayList<TestIdentifier> batchTests = new ArrayList<>(TESTCASE_BATCH_LIMIT);
+            for (TestIdentifier test : mRemainingTests) {
+                batchTests.add(test);
+                if (batchTests.size() >= TESTCASE_BATCH_LIMIT) {
+                    break;
+                }
+            }
 
-        mDevice.executeShellCommand("rm " + caseListFileName);
-        mDevice.executeShellCommand("rm " + logFileName);
-        mDevice.pushString(testCases + "\n", caseListFileName);
+            // find union of all run configurations
+            final Set<BatchRunConfiguration> allConfigs = new LinkedHashSet<>();
+            for (TestIdentifier test : batchTests) {
+                allConfigs.addAll(getTestRunConfigs(test));
+            }
 
-        String instrumentationName =
+            // prepare instance listener
+            for (TestIdentifier test : batchTests) {
+                mInstanceListerner.setTestInstances(test, getTestRunConfigs(test));
+            }
+
+            // run batch for all configurations
+            for (BatchRunConfiguration runConfig : allConfigs) {
+                final ArrayList<TestIdentifier> relevantTests =
+                        new ArrayList<>(TESTCASE_BATCH_LIMIT);
+
+                // run only for declared run configs and only if test has not already
+                // been attempted to run
+                for (TestIdentifier test : batchTests) {
+                    if (mInstanceListerner.isPendingTestInstance(test, runConfig)) {
+                        relevantTests.add(test);
+                    }
+                }
+
+                if (!relevantTests.isEmpty()) {
+                    runTestRunBatch(relevantTests, runConfig);
+                }
+            }
+        }
+    }
+
+    private void runTestRunBatch(Collection<TestIdentifier> tests, BatchRunConfiguration runConfig)
+            throws DeviceNotAvailableException, CapabilityQueryFailureException {
+        boolean isSupportedConfig = true;
+
+        // orientation support
+        if (!BatchRunConfiguration.ROTATION_UNSPECIFIED.equals(runConfig.getRotation())) {
+            final Set<String> features = getDeviceFeatures(mDevice);
+
+            if (isPortraitClassRotation(runConfig.getRotation()) &&
+                    !features.contains(FEATURE_PORTRAIT)) {
+                isSupportedConfig = false;
+            }
+            if (isLandscapeClassRotation(runConfig.getRotation()) &&
+                    !features.contains(FEATURE_LANDSCAPE)) {
+                isSupportedConfig = false;
+            }
+        }
+
+        // renderability support for OpenGL ES tests
+        if (isSupportedConfig && isOpenGlEsPackage()) {
+            isSupportedConfig = isSupportedGlesRenderConfig(runConfig);
+        }
+
+        mInstanceListerner.setCurrentConfig(runConfig);
+
+        // execute only if config is executable, else fake results
+        if (isSupportedConfig) {
+            executeTestRunBatch(tests, runConfig);
+        } else {
+            fakePassTestRunBatch(tests, runConfig);
+        }
+    }
+
+    private void executeTestRunBatch(Collection<TestIdentifier> tests,
+            BatchRunConfiguration runConfig) throws DeviceNotAvailableException {
+        final String testCases = generateTestCaseTrie(tests);
+
+        mDevice.executeShellCommand("rm " + CASE_LIST_FILE_NAME);
+        mDevice.executeShellCommand("rm " + LOG_FILE_NAME);
+        mDevice.pushString(testCases + "\n", CASE_LIST_FILE_NAME);
+
+        final String instrumentationName =
                 "com.drawelements.deqp/com.drawelements.deqp.testercore.DeqpInstrumentation";
 
-        String command = String.format(
-                "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
-                    + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8\""
-                    + " -e deqpLogData \"%s\" %s",
-                AbiUtils.createAbiFlag(mAbi.getName()), logFileName, caseListFileName, mLogData,
-                instrumentationName);
+        final StringBuilder deqpCmdLine = new StringBuilder();
+        deqpCmdLine.append("--deqp-caselist-file=");
+        deqpCmdLine.append(CASE_LIST_FILE_NAME);
+        deqpCmdLine.append(" ");
+        deqpCmdLine.append(getRunConfigDisplayCmdLine(runConfig));
 
-        mDevice.executeShellCommand(command, parser);
-        parser.flush();
+        // If we are not logging data, do not bother outputting the images from the test exe.
+        if (!mLogData) {
+            deqpCmdLine.append(" --deqp-log-images=disable");
+        }
+
+        final String command = String.format(
+                "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \"%s\""
+                    + " -e deqpLogData \"%s\" %s",
+                AbiUtils.createAbiFlag(mAbi.getName()), LOG_FILE_NAME, deqpCmdLine.toString(),
+                mLogData, instrumentationName);
+
+        try {
+            final InstrumentationParser parser = new InstrumentationParser(mInstanceListerner);
+            mDevice.executeShellCommand(command, parser);
+            parser.flush();
+        } catch (DeviceNotAvailableException ex) {
+            // Device lost. We must signal the tradedef by rethrowing this execption. However,
+            // there is a possiblity that the device loss was caused by the currently run test
+            // instance. Since CtsTest is unaware of tests with only some instances executed,
+            // continuing the session after device has recovered will create a new DeqpTestRunner
+            // with current test in its run queue and this will cause the re-execution of this same
+            // instance. If the instance reliably can kill the device, the CTS cannot recover.
+            //
+            // Prevent this by terminating ALL instances of a tests if any of them causes a device
+            // loss.
+            mInstanceListerner.onDeviceLost();
+            throw ex;
+        } finally {
+            mInstanceListerner.endBatch();
+        }
+    }
+
+    private static String getRunConfigDisplayCmdLine(BatchRunConfiguration runConfig) {
+        final StringBuilder deqpCmdLine = new StringBuilder();
+        if (!runConfig.getGlConfig().isEmpty()) {
+            deqpCmdLine.append("--deqp-gl-config-name=");
+            deqpCmdLine.append(runConfig.getGlConfig());
+        }
+        if (!runConfig.getRotation().isEmpty()) {
+            if (deqpCmdLine.length() != 0) {
+                deqpCmdLine.append(" ");
+            }
+            deqpCmdLine.append("--deqp-screen-rotation=");
+            deqpCmdLine.append(runConfig.getRotation());
+        }
+        if (!runConfig.getSurfaceType().isEmpty()) {
+            if (deqpCmdLine.length() != 0) {
+                deqpCmdLine.append(" ");
+            }
+            deqpCmdLine.append("--deqp-surface-type=");
+            deqpCmdLine.append(runConfig.getSurfaceType());
+        }
+        return deqpCmdLine.toString();
+    }
+
+    /**
+     * Pass given batch tests without running it
+     */
+    private void fakePassTestRunBatch(Collection<TestIdentifier> tests,
+            BatchRunConfiguration runConfig) {
+        for (TestIdentifier test : tests) {
+            CLog.d("Skipping test '%s' invocation in config '%s'", test.toString(),
+                    runConfig.getId());
+            mInstanceListerner.skipTest(test);
+        }
+    }
+
+    /**
+     * Pass all remaining tests without running them
+     */
+    private void fakePassTests(ITestInvocationListener listener) {
+        Map <String, String> emptyMap = Collections.emptyMap();
+        for (TestIdentifier test : mRemainingTests) {
+            CLog.d("Skipping test '%s', Opengl ES version not supported", test.toString());
+            listener.testStarted(test);
+            listener.testEnded(test, emptyMap);
+        }
+        mRemainingTests.clear();
     }
 
     /**
      * Check if device supports OpenGL ES version.
      */
-    static boolean isSupportedGles(ITestDevice device, int requiredMajorVersion, int requiredMinorVersion) throws DeviceNotAvailableException {
+    private static boolean isSupportedGles(ITestDevice device, int requiredMajorVersion,
+            int requiredMinorVersion) throws DeviceNotAvailableException {
         String roOpenglesVersion = device.getProperty("ro.opengles.version");
 
         if (roOpenglesVersion == null)
@@ -450,6 +946,99 @@
     }
 
     /**
+     * Query if rendertarget is supported
+     */
+    private boolean isSupportedGlesRenderConfig(BatchRunConfiguration runConfig)
+            throws DeviceNotAvailableException, CapabilityQueryFailureException {
+        // query if configuration is supported
+        final StringBuilder configCommandLine =
+                new StringBuilder(getRunConfigDisplayCmdLine(runConfig));
+        if (configCommandLine.length() != 0) {
+            configCommandLine.append(" ");
+        }
+        configCommandLine.append("--deqp-gl-major-version=");
+        configCommandLine.append(getGlesMajorVersion());
+        configCommandLine.append(" --deqp-gl-minor-version=");
+        configCommandLine.append(getGlesMinorVersion());
+
+        final String instrumentationName =
+                "com.drawelements.deqp/com.drawelements.deqp.platformutil.DeqpPlatformCapabilityQueryInstrumentation";
+        final String command = String.format(
+                "am instrument %s -w -e deqpQueryType renderConfigSupported -e deqpCmdLine \"%s\""
+                    + " %s",
+                AbiUtils.createAbiFlag(mAbi.getName()), configCommandLine.toString(),
+                instrumentationName);
+
+        final PlatformQueryInstrumentationParser parser = new PlatformQueryInstrumentationParser();
+        mDevice.executeShellCommand(command, parser);
+        parser.flush();
+
+        if (parser.wasSuccessful() && parser.getResultCode() == 0 &&
+                parser.getResultMap().containsKey("Supported")) {
+            if ("Yes".equals(parser.getResultMap().get("Supported"))) {
+                return true;
+            } else if ("No".equals(parser.getResultMap().get("Supported"))) {
+                return false;
+            } else {
+                CLog.e("Capability query did not return a result");
+                throw new CapabilityQueryFailureException();
+            }
+        } else if (parser.wasSuccessful()) {
+            CLog.e("Failed to run capability query. Code: %d, Result: %s",
+                    parser.getResultCode(), parser.getResultMap().toString());
+            throw new CapabilityQueryFailureException();
+        } else {
+            CLog.e("Failed to run capability query");
+            throw new CapabilityQueryFailureException();
+        }
+    }
+
+    /**
+     * Return feature set supported by the device
+     */
+    private Set<String> getDeviceFeatures(ITestDevice device)
+            throws DeviceNotAvailableException, CapabilityQueryFailureException {
+        if (mDeviceFeatures == null) {
+            mDeviceFeatures = queryDeviceFeatures(device);
+        }
+        return mDeviceFeatures;
+    }
+
+    /**
+     * Query feature set supported by the device
+     */
+    private static Set<String> queryDeviceFeatures(ITestDevice device)
+            throws DeviceNotAvailableException, CapabilityQueryFailureException {
+        // NOTE: Almost identical code in BaseDevicePolicyTest#hasDeviceFeatures
+        // TODO: Move this logic to ITestDevice.
+        String command = "pm list features";
+        String commandOutput = device.executeShellCommand(command);
+
+        // Extract the id of the new user.
+        HashSet<String> availableFeatures = new HashSet<>();
+        for (String feature: commandOutput.split("\\s+")) {
+            // Each line in the output of the command has the format "feature:{FEATURE_VALUE}".
+            String[] tokens = feature.split(":");
+            if (tokens.length < 2 || !"feature".equals(tokens[0])) {
+                CLog.e("Failed parse features. Unexpect format on line \"%s\"", tokens[0]);
+                throw new CapabilityQueryFailureException();
+            }
+            availableFeatures.add(tokens[1]);
+        }
+        return availableFeatures;
+    }
+
+    private boolean isPortraitClassRotation(String rotation) {
+        return BatchRunConfiguration.ROTATION_PORTRAIT.equals(rotation) ||
+                BatchRunConfiguration.ROTATION_REVERSE_PORTRAIT.equals(rotation);
+    }
+
+    private boolean isLandscapeClassRotation(String rotation) {
+        return BatchRunConfiguration.ROTATION_LANDSCAPE.equals(rotation) ||
+                BatchRunConfiguration.ROTATION_REVERSE_LANDSCAPE.equals(rotation);
+    }
+
+    /**
      * Install dEQP OnDevice Package
      */
     private void installTestApk() throws DeviceNotAvailableException {
@@ -473,60 +1062,53 @@
     }
 
     /**
-     * {@inheritDoc}
+     * Parse gl nature from package name
      */
-    @Override
-    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
-        mListener = listener;
-
-        if ((mName.equals( "dEQP-GLES3") && isSupportedGles(mDevice, 3, 0))
-            || (mName.equals("dEQP-GLES31") && isSupportedGles(mDevice, 3, 1))) {
-
-            // Make sure there is no pre-existing package form earlier interrupted test run.
-            uninstallTestApk();
-            installTestApk();
-
-            while (!mTests.isEmpty()) {
-                executeTests(listener);
-
-                // Set test to failed if it didn't receive test result
-                if (mCurrentTestId != null) {
-                    Map <String, String> emptyMap = Collections.emptyMap();
-
-                    if (mLogData && mCurrentTestLog != null && mCurrentTestLog.length() > 0) {
-                        ByteArrayInputStreamSource source
-                                = new ByteArrayInputStreamSource(mCurrentTestLog.getBytes());
-
-                        mListener.testLog(mCurrentTestId.getClassName() + "."
-                                + mCurrentTestId.getTestName(), LogDataType.XML, source);
-
-                        source.cancel();
-                    }
-                    if (!mGotTestResult) {
-                        mListener.testFailed(mCurrentTestId,
-                            INCOMPLETE_LOG_MESSAGE);
-                    }
-
-                    mListener.testEnded(mCurrentTestId, emptyMap);
-                    mCurrentTestId = null;
-                    mListener.testRunEnded(0, emptyMap);
-                }
-            }
-
-            uninstallTestApk();
+    private boolean isOpenGlEsPackage() {
+        if ("dEQP-GLES2".equals(mName) || "dEQP-GLES3".equals(mName) ||
+                "dEQP-GLES31".equals(mName)) {
+            return true;
+        } else if ("dEQP-EGL".equals(mName)) {
+            return false;
         } else {
-            /* Pass all tests if OpenGL ES version is not supported */
-            Map <String, String> emptyMap = Collections.emptyMap();
-            String id = AbiUtils.createId(mAbi.getName(), mPackageName);
-            mListener.testRunStarted(id, mTests.size());
+            throw new IllegalStateException("dEQP runner was created with illegal name");
+        }
+    }
 
-            for (TestIdentifier test : mTests) {
-                CLog.d("Skipping test '%s', Opengl ES version not supported", test.toString());
-                mListener.testStarted(test);
-                mListener.testEnded(test, emptyMap);
-            }
+    /**
+     * Check GL support (based on package name)
+     */
+    private boolean isSupportedGles() throws DeviceNotAvailableException {
+        return isSupportedGles(mDevice, getGlesMajorVersion(), getGlesMinorVersion());
+    }
 
-            mListener.testRunEnded(0, emptyMap);
+    /**
+     * Get GL major version (based on package name)
+     */
+    private int getGlesMajorVersion() throws DeviceNotAvailableException {
+        if ("dEQP-GLES2".equals(mName)) {
+            return 2;
+        } else if ("dEQP-GLES3".equals(mName)) {
+            return 3;
+        } else if ("dEQP-GLES31".equals(mName)) {
+            return 3;
+        } else {
+            throw new IllegalStateException("getGlesMajorVersion called for non gles pkg");
+        }
+    }
+
+    /**
+     * Get GL minor version (based on package name)
+     */
+    private int getGlesMinorVersion() throws DeviceNotAvailableException {
+        if ("dEQP-GLES2".equals(mName)) {
+            return 0;
+        } else if ("dEQP-GLES3".equals(mName)) {
+            return 0;
+        } else if ("dEQP-GLES31".equals(mName)) {
+            return 1;
+        } else {
+            throw new IllegalStateException("getGlesMinorVersion called for non gles pkg");
         }
     }
 
@@ -534,15 +1116,33 @@
      * {@inheritDoc}
      */
     @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        final Map<String, String> emptyMap = Collections.emptyMap();
+        final boolean isSupportedApi = !isOpenGlEsPackage() || isSupportedGles();
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
+        listener.testRunStarted(getId(), mRemainingTests.size());
+
+        try {
+            if (isSupportedApi) {
+                // Make sure there is no pre-existing package form earlier interrupted test run.
+                uninstallTestApk();
+                installTestApk();
+
+                mInstanceListerner.setSink(listener);
+                runTests();
+
+                uninstallTestApk();
+            } else {
+                // Pass all tests if OpenGL ES version is not supported
+                fakePassTests(listener);
+            }
+        } catch (CapabilityQueryFailureException ex) {
+            // Platform is not behaving correctly, for example crashing when trying to create
+            // a window. Instead of silenty failing, signal failure by leaving the rest of the
+            // test cases in "NotExecuted" state
+            uninstallTestApk();
+        }
+
+        listener.testRunEnded(0, emptyMap);
     }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DisplayTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DisplayTestRunner.java
deleted file mode 100644
index 59bfcf8..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DisplayTestRunner.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.tradefed.testtype;
-
-import com.android.cts.tradefed.targetprep.SettingsToggler;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.result.ITestInvocationListener;
-
-/**
- * Running the display tests requires modification of secure settings to create an overlay display.
- * Secure settings cannot be changed from device CTS tests since system signature permission is
- * required. Such settings can be modified by the shell user, so a host side test is used.
- */
-public class DisplayTestRunner extends CtsInstrumentationApkTest {
-    private static final String OVERLAY_DISPLAY_DEVICES_SETTING_NAME = "overlay_display_devices";
-
-    // Use a non-standard pattern, must match values in tests/tests/display/.../DisplayTest.java
-    private static final String OVERLAY_DISPLAY_DEVICES_SETTING_VALUE = "1281x721/214";
-
-    @Override
-    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
-        // CLog.e("run: About to enable overlay display.");
-        SettingsToggler.setGlobalString(getDevice(), OVERLAY_DISPLAY_DEVICES_SETTING_NAME,
-                OVERLAY_DISPLAY_DEVICES_SETTING_VALUE);
-
-        super.run(listener);
-
-        // Tear down overlay display.
-        // CLog.e("run: About to disable overlay display.");
-        SettingsToggler.setGlobalString(getDevice(), OVERLAY_DISPLAY_DEVICES_SETTING_NAME,
-                "");
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
index 6c2ed65..2e4420d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
@@ -29,6 +29,8 @@
 import com.android.tradefed.testtype.IRemoteTest;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Test runner for native gTests.
@@ -43,6 +45,7 @@
     private static final String NATIVE_TESTS_DIRECTORY = "/data/local/tmp/cts-native-tests";
     private static final String NATIVE_TESTS_DIRECTORY_TMP = "/data/local/tmp";
     private static final String ANDROID_PATH_SEPARATOR = "/";
+    private static final String GTEST_FLAG_FILTER = "--gtest_filter=";
 
     private int mMaxTestTimeMs = 1 * 60 * 1000;
 
@@ -53,11 +56,48 @@
 
     private final String mPackageName;
 
+    private String mPositiveFilters = "";
+    private String mNegativeFilters = "";
+
     public GeeTest(String packageName, String exeName) {
         mPackageName = packageName;
         mExeName = exeName;
     }
 
+    public void setPositiveFilters(String positiveFilters) {
+        mPositiveFilters = positiveFilters;
+    }
+
+    public void setNegativeFilters(String negativeFilters) {
+        mNegativeFilters = negativeFilters;
+    }
+
+    protected String getGTestFilters() {
+        // If both filters are empty or null return empty string.
+        if (mPositiveFilters == null && mNegativeFilters == null) {
+            return "";
+        }
+        if (mPositiveFilters.isEmpty() && mNegativeFilters.isEmpty()) {
+            return "";
+        }
+        // Build filter string.
+        StringBuilder sb = new StringBuilder();
+        sb.append(GTEST_FLAG_FILTER);
+        boolean hasPositiveFilters = false;
+        if (mPositiveFilters != null && !mPositiveFilters.isEmpty()) {
+            sb.append(mPositiveFilters);
+            hasPositiveFilters = true;
+        }
+        if (mNegativeFilters != null && ! mNegativeFilters.isEmpty()) {
+            if (hasPositiveFilters) {
+                sb.append(":");
+            }
+            sb.append("-");
+            sb.append(mNegativeFilters);
+        }
+        return sb.toString();
+    }
+
     /**
      * @param abi The ABI to run the test on
      */
@@ -113,7 +153,7 @@
         resultParser.setFakePackagePrefix(mPackageName + ".");
 
         String fullPath = NATIVE_TESTS_DIRECTORY + ANDROID_PATH_SEPARATOR + mExeName;
-        String flags = "";
+        String flags = getGTestFilters();
         CLog.v("Running gtest %s %s on %s", fullPath, flags, mDevice.getSerialNumber());
         // force file to be executable
         CLog.v("%s", mDevice.executeShellCommand(String.format("chmod 755 %s", fullPath)));
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
index 8a5c822..13f3572 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
@@ -17,11 +17,13 @@
 package com.android.cts.tradefed.testtype;
 
 import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.targetprep.ITargetPreparer;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IRemoteTest;
 
 import java.io.File;
 import java.util.Collection;
+import java.util.List;
 
 /**
  * Container for CTS test info.
@@ -98,4 +100,9 @@
      */
     public String getTargetPackageName();
 
+    /**
+     * Return a list of preparers used for setup or teardown of test cases in this package
+     * @return
+     */
+    public List<ITargetPreparer> getPackagePreparers();
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRemoteTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRemoteTestRunner.java
deleted file mode 100644
index 72dccd4..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRemoteTestRunner.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * 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.cts.tradefed.testtype;
-
-import com.android.ddmlib.AdbCommandRejectedException;
-import com.android.ddmlib.IShellEnabledDevice;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.ShellCommandUnresponsiveException;
-import com.android.ddmlib.TimeoutException;
-import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.ITestRunListener;
-import com.android.ddmlib.testrunner.InstrumentationResultParser;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.TimeUnit;
-
-public class PrintTestRemoteTestRunner implements IRemoteAndroidTestRunner {
-
-    private final String mPackageName;
-    private final String mRunnerName;
-    private IShellEnabledDevice mRemoteDevice;
-    // default to no timeout
-    private long mMaxTimeToOutputResponse = 0;
-    private TimeUnit mMaxTimeUnits = TimeUnit.MILLISECONDS;
-    private String mRunName = null;
-
-    /** map of name-value instrumentation argument pairs */
-    private Map<String, String> mArgMap;
-    private InstrumentationResultParser mParser;
-
-    private static final String LOG_TAG = "RemoteAndroidTest";
-    private static final String DEFAULT_RUNNER_NAME = "android.test.InstrumentationTestRunner";
-
-    private static final char CLASS_SEPARATOR = ',';
-    private static final char METHOD_SEPARATOR = '#';
-    private static final char RUNNER_SEPARATOR = '/';
-
-    // defined instrumentation argument names
-    private static final String CLASS_ARG_NAME = "class";
-    private static final String LOG_ARG_NAME = "log";
-    private static final String DEBUG_ARG_NAME = "debug";
-    private static final String COVERAGE_ARG_NAME = "coverage";
-    private static final String PACKAGE_ARG_NAME = "package";
-    private static final String SIZE_ARG_NAME = "size";
-
-    // This command starts a shell Java program (installed by this class)
-    // in the folder owned by the shell user. This app creates a proxy
-    // which does privileged operations such as wiping a package's user
-    // data and then starts the tests passing the proxy. This enables
-    // the tests to clear the print spooler data.
-    private static final String INSTRUMENTATION_COMMAND =
-            "chmod 755 /data/local/tmp/print-instrument && "
-            + "/data/local/tmp/print-instrument instrument -w -r %1$s %2$s";
-
-    /**
-     * Creates a remote Android test runner.
-     *
-     * @param packageName the Android application package that contains the
-     *            tests to run
-     * @param runnerName the instrumentation test runner to execute. If null,
-     *            will use default runner
-     * @param remoteDevice the Android device to execute tests on
-     */
-    public PrintTestRemoteTestRunner(String packageName, String runnerName,
-            IShellEnabledDevice remoteDevice) {
-
-        mPackageName = packageName;
-        mRunnerName = runnerName;
-        mRemoteDevice = remoteDevice;
-        mArgMap = new Hashtable<String, String>();
-    }
-
-    /**
-     * Alternate constructor. Uses default instrumentation runner.
-     *
-     * @param packageName the Android application package that contains the
-     *            tests to run
-     * @param remoteDevice the Android device to execute tests on
-     */
-    public PrintTestRemoteTestRunner(String packageName, IShellEnabledDevice remoteDevice) {
-        this(packageName, null, remoteDevice);
-    }
-
-    @Override
-    public String getPackageName() {
-        return mPackageName;
-    }
-
-    @Override
-    public String getRunnerName() {
-        if (mRunnerName == null) {
-            return DEFAULT_RUNNER_NAME;
-        }
-        return mRunnerName;
-    }
-
-    /**
-     * Returns the complete instrumentation component path.
-     */
-    private String getRunnerPath() {
-        return getPackageName() + RUNNER_SEPARATOR + getRunnerName();
-    }
-
-    @Override
-    public void setClassName(String className) {
-        addInstrumentationArg(CLASS_ARG_NAME, className);
-    }
-
-    @Override
-    public void setClassNames(String[] classNames) {
-        StringBuilder classArgBuilder = new StringBuilder();
-
-        for (int i = 0; i < classNames.length; i++) {
-            if (i != 0) {
-                classArgBuilder.append(CLASS_SEPARATOR);
-            }
-            classArgBuilder.append(classNames[i]);
-        }
-        setClassName(classArgBuilder.toString());
-    }
-
-    @Override
-    public void setMethodName(String className, String testName) {
-        setClassName(className + METHOD_SEPARATOR + testName);
-    }
-
-    @Override
-    public void setTestPackageName(String packageName) {
-        addInstrumentationArg(PACKAGE_ARG_NAME, packageName);
-    }
-
-    @Override
-    public void addInstrumentationArg(String name, String value) {
-        if (name == null || value == null) {
-            throw new IllegalArgumentException("name or value arguments cannot be null");
-        }
-        mArgMap.put(name, value);
-    }
-
-    @Override
-    public void removeInstrumentationArg(String name) {
-        if (name == null) {
-            throw new IllegalArgumentException("name argument cannot be null");
-        }
-        mArgMap.remove(name);
-    }
-
-    @Override
-    public void addBooleanArg(String name, boolean value) {
-        addInstrumentationArg(name, Boolean.toString(value));
-    }
-
-    @Override
-    public void setLogOnly(boolean logOnly) {
-        addBooleanArg(LOG_ARG_NAME, logOnly);
-    }
-
-    @Override
-    public void setDebug(boolean debug) {
-        addBooleanArg(DEBUG_ARG_NAME, debug);
-    }
-
-    @Override
-    public void setCoverage(boolean coverage) {
-        addBooleanArg(COVERAGE_ARG_NAME, coverage);
-    }
-
-    @Override
-    public void setTestCollection(boolean b) {
-        throw new UnsupportedOperationException("Test Collection mode is not supported");
-    }
-
-    @Override
-    public void setTestSize(TestSize size) {
-        addInstrumentationArg(SIZE_ARG_NAME, ""/*size.getRunnerValue()*/);
-    }
-
-    @Override
-    public void setMaxtimeToOutputResponse(int maxTimeToOutputResponse) {
-        setMaxTimeToOutputResponse(maxTimeToOutputResponse, TimeUnit.MILLISECONDS);
-    }
-
-    @Override
-    public void setMaxTimeToOutputResponse(long maxTimeToOutputResponse, TimeUnit maxTimeUnits) {
-        mMaxTimeToOutputResponse = maxTimeToOutputResponse;
-        mMaxTimeUnits = maxTimeUnits;
-    }
-
-    @Override
-    public void setRunName(String runName) {
-        mRunName = runName;
-    }
-
-    @Override
-    public void run(ITestRunListener... listeners) throws TimeoutException,
-            AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
-        run(Arrays.asList(listeners));
-    }
-
-    @Override
-    public void run(Collection<ITestRunListener> listeners) throws TimeoutException,
-            AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
-        final String runCaseCommandStr = String.format(INSTRUMENTATION_COMMAND,
-              getArgsCommand(), getRunnerPath());
-        Log.i(LOG_TAG,
-                String.format("Running %1$s on %2$s", runCaseCommandStr, mRemoteDevice.getName()));
-        String runName = mRunName == null ? mPackageName : mRunName;
-        mParser = new InstrumentationResultParser(runName, listeners);
-
-        try {
-            mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser, mMaxTimeToOutputResponse,
-                    mMaxTimeUnits);
-        } catch (IOException e) {
-            Log.w(LOG_TAG, String.format("IOException %1$s when running tests %2$s on %3$s",
-                    e.toString(), getPackageName(), mRemoteDevice.getName()));
-            // rely on parser to communicate results to listeners
-            mParser.handleTestRunFailed(e.toString());
-            throw e;
-        } catch (ShellCommandUnresponsiveException e) {
-            Log.w(LOG_TAG, String.format(
-                    "ShellCommandUnresponsiveException %1$s when running tests %2$s on %3$s",
-                    e.toString(), getPackageName(), mRemoteDevice.getName()));
-            mParser.handleTestRunFailed(String
-                    .format("Failed to receive adb shell test output within %1$d ms. "
-                            + "Test may have timed out, or adb connection to device became"
-                            + "unresponsive", mMaxTimeToOutputResponse));
-            throw e;
-        } catch (TimeoutException e) {
-            Log.w(LOG_TAG, String.format("TimeoutException when running tests %1$s on %2$s",
-                    getPackageName(), mRemoteDevice.getName()));
-            mParser.handleTestRunFailed(e.toString());
-            throw e;
-        } catch (AdbCommandRejectedException e) {
-            Log.w(LOG_TAG, String.format(
-                    "AdbCommandRejectedException %1$s when running tests %2$s on %3$s",
-                    e.toString(), getPackageName(), mRemoteDevice.getName()));
-            mParser.handleTestRunFailed(e.toString());
-            throw e;
-        }
-    }
-
-    @Override
-    public void cancel() {
-        if (mParser != null) {
-            mParser.cancel();
-        }
-    }
-
-    /**
-     * Returns the full instrumentation command line syntax for the provided
-     * instrumentation arguments. Returns an empty string if no arguments were
-     * specified.
-     */
-    private String getArgsCommand() {
-        StringBuilder commandBuilder = new StringBuilder();
-        for (Entry<String, String> argPair : mArgMap.entrySet()) {
-            final String argCmd = String.format(" -e %1$s %2$s", argPair.getKey(),
-                    argPair.getValue());
-            commandBuilder.append(argCmd);
-        }
-        return commandBuilder.toString();
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRunner.java
deleted file mode 100644
index 44d2d3a..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRunner.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * 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.cts.tradefed.testtype;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.tradefed.targetprep.SettingsToggler;
-import com.android.cts.util.AbiUtils;
-import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner.TestSize;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IBuildReceiver;
-import com.android.tradefed.testtype.IDeviceTest;
-import com.android.tradefed.testtype.IRemoteTest;
-import com.android.tradefed.util.StringEscapeUtils;
-
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Running the print tests requires modification of secure settings. Secure
- * settings cannot be changed from device CTS tests since system signature
- * permission is required. Such settings can be modified by the shell user,
- * so a host side test driver is used for enabling these services, running
- * the tests, and disabling the services.
- */
-public class PrintTestRunner implements IBuildReceiver, IRemoteTest, IDeviceTest  {
-
-    private static final String PRINT_TEST_AND_SERVICES_APP_NAME =
-            "CtsPrintTestCases.apk";
-
-    private static final String PRINT_TESTS_PACKAGE_NAME =
-            "com.android.cts.print";
-
-    private static final String FIRST_PRINT_SERVICE_NAME =
-            "android.print.cts.services.FirstPrintService";
-
-    private static final String SECOND_PRINT_SERVICE_NAME =
-            "android.print.cts.services.SecondPrintService";
-
-    private static final String SHELL_USER_FOLDER = "data/local/tmp";
-
-    private static final String PRINT_INSTRUMENT_JAR = "CtsPrintInstrument.jar";
-
-    private static final String PRINT_INSTRUMENT_SCRIPT = "print-instrument";
-
-    private ITestDevice mDevice;
-
-    private CtsBuildHelper mCtsBuild;
-
-    private IAbi mAbi;
-    private String mPackageName;
-    private String mRunnerName = "android.test.InstrumentationTestRunner";
-    private String mTestClassName;
-    private String mTestMethodName;
-    private String mTestPackageName;
-    private int mTestTimeout = 10 * 60 * 1000;  // 10 minutes
-    private String mTestSize;
-    private String mRunName = null;
-    private Map<String, String> mInstrArgMap = new HashMap<String, String>();
-
-    /**
-     * @param abi The ABI to run the test on
-     */
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    public void setDevice(ITestDevice device) {
-        mDevice = device;
-    }
-
-    @Override
-    public ITestDevice getDevice() {
-        return mDevice;
-    }
-
-    public void setPackageName(String packageName) {
-        mPackageName = packageName;
-    }
-
-    public void setRunnerName(String runnerName) {
-        mRunnerName = runnerName;
-    }
-
-    public void setClassName(String testClassName) {
-        mTestClassName = testClassName;
-    }
-
-    public void setMethodName(String testMethodName) {
-        mTestMethodName = StringEscapeUtils.escapeShell(testMethodName);
-    }
-
-    public void setTestPackageName(String testPackageName) {
-        mTestPackageName = testPackageName;
-    }
-
-    public void setTestSize(String size) {
-        mTestSize = size;
-    }
-
-    public void setRunName(String runName) {
-        mRunName = runName;
-    }
-
-    @Override
-    public void run(final ITestInvocationListener listener) throws DeviceNotAvailableException {
-        installShellProgramAndScriptFiles();
-        installTestsAndServicesApk();
-        enablePrintServices();
-        doRunTests(listener);
-        disablePrintServices();
-        uninstallTestsAndServicesApk();
-        uninstallShellProgramAndScriptFiles();
-    }
-
-    private void doRunTests(ITestInvocationListener listener)
-            throws DeviceNotAvailableException {
-        if (mPackageName == null) {
-            throw new IllegalArgumentException("package name has not been set");
-        }
-        if (mDevice == null) {
-            throw new IllegalArgumentException("Device has not been set");
-        }
-
-        IRemoteAndroidTestRunner runner =  new PrintTestRemoteTestRunner(mPackageName,
-                mRunnerName, mDevice.getIDevice());
-
-        if (mTestClassName != null) {
-            if (mTestMethodName != null) {
-                runner.setMethodName(mTestClassName, mTestMethodName);
-            } else {
-                runner.setClassName(mTestClassName);
-            }
-        } else if (mTestPackageName != null) {
-            runner.setTestPackageName(mTestPackageName);
-        }
-        if (mTestSize != null) {
-            runner.setTestSize(TestSize.getTestSize(mTestSize));
-        }
-        runner.setMaxTimeToOutputResponse(mTestTimeout, TimeUnit.MILLISECONDS);
-        if (mRunName != null) {
-            runner.setRunName(mRunName);
-        }
-        for (Map.Entry<String, String> argEntry : mInstrArgMap.entrySet()) {
-            runner.addInstrumentationArg(argEntry.getKey(), argEntry.getValue());
-        }
-
-        mDevice.runInstrumentationTests(runner, listener);
-    }
-
-    private void installShellProgramAndScriptFiles() throws DeviceNotAvailableException {
-        installFile(PRINT_INSTRUMENT_JAR);
-        installFile(PRINT_INSTRUMENT_SCRIPT);
-    }
-
-    private void installFile(String fileName) throws DeviceNotAvailableException {
-        try {
-            final boolean success = getDevice().pushFile(mCtsBuild.getTestApp(
-                    fileName), SHELL_USER_FOLDER + "/" + fileName);
-            if (!success) {
-                throw new IllegalArgumentException("Failed to install "
-                        + fileName + " on " + getDevice().getSerialNumber());
-           }
-        } catch (FileNotFoundException fnfe) {
-            throw new IllegalArgumentException("Cannot find file: " + fileName);
-        }
-    }
-
-    private void uninstallShellProgramAndScriptFiles() throws DeviceNotAvailableException {
-        getDevice().executeShellCommand("rm " + SHELL_USER_FOLDER + "/"
-                + PRINT_INSTRUMENT_JAR);
-        getDevice().executeShellCommand("rm " + SHELL_USER_FOLDER + "/"
-                + PRINT_INSTRUMENT_SCRIPT);
-    }
-
-    private void installTestsAndServicesApk() throws DeviceNotAvailableException {
-        try {
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            String installCode = getDevice().installPackage(mCtsBuild.getTestApp(
-                    PRINT_TEST_AND_SERVICES_APP_NAME), true, options);
-            if (installCode != null) {
-                throw new IllegalArgumentException("Failed to install "
-                        + PRINT_TEST_AND_SERVICES_APP_NAME + " on " + getDevice().getSerialNumber()
-                        + ". Reason: " + installCode);
-           }
-        } catch (FileNotFoundException fnfe) {
-            throw new IllegalArgumentException("Cannot find file: "
-                    + PRINT_TEST_AND_SERVICES_APP_NAME);
-        }
-    }
-
-    private void uninstallTestsAndServicesApk() throws DeviceNotAvailableException {
-        getDevice().uninstallPackage(PRINT_TESTS_PACKAGE_NAME);
-    }
-
-    private void enablePrintServices() throws DeviceNotAvailableException {
-        String enabledServicesValue = PRINT_TESTS_PACKAGE_NAME + "/" + FIRST_PRINT_SERVICE_NAME
-                + ":" + PRINT_TESTS_PACKAGE_NAME + "/" + SECOND_PRINT_SERVICE_NAME;
-        SettingsToggler.setSecureString(getDevice(), "enabled_print_services",
-                enabledServicesValue);
-    }
-
-    private void disablePrintServices() throws DeviceNotAvailableException {
-        SettingsToggler.setSecureString(getDevice(), "enabled_print_services", "");
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index 9ef6257..f276f1d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -20,6 +20,7 @@
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.ITargetPreparer;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.InstrumentationTest;
@@ -35,7 +36,11 @@
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Container for CTS test info.
@@ -49,14 +54,6 @@
     public static final String WRAPPED_NATIVE_TEST = "wrappednative";
     public static final String VM_HOST_TEST = "vmHostTest";
     public static final String DEQP_TEST = "deqpTest";
-    public static final String ACCESSIBILITY_TEST =
-            "com.android.cts.tradefed.testtype.AccessibilityTestRunner";
-    public static final String ACCESSIBILITY_SERVICE_TEST =
-            "com.android.cts.tradefed.testtype.AccessibilityServiceTestRunner";
-    public static final String PRINT_TEST =
-            "com.android.cts.tradefed.testtype.PrintTestRunner";
-    public static final String DISPLAY_TEST =
-            "com.android.cts.tradefed.testtype.DisplayTestRunner";
     public static final String UIAUTOMATOR_TEST = "uiAutomator";
     public static final String JUNIT_DEVICE_TEST = "jUnitDeviceTest";
 
@@ -70,12 +67,16 @@
     private String mTestPackageName = null;
     private String mDigest = null;
     private IAbi mAbi = null;
+    private List<ITargetPreparer> mPreparers = null;
 
     // use a LinkedHashSet for predictable iteration insertion-order, and fast
     // lookups
     private Collection<TestIdentifier> mTests = new LinkedHashSet<TestIdentifier>();
     // also maintain an index of known test classes
     private Collection<String> mTestClasses = new LinkedHashSet<String>();
+    // store instance arguments in order too for consistency
+    private Map<TestIdentifier, List<Map<String, String>>> mTestInstanceArguments =
+            new LinkedHashMap<>();
 
     // dynamic options, not parsed from package xml
     private String mClassName;
@@ -210,6 +211,22 @@
     }
 
     /**
+     * Setter for injecting a list of {@link ITargetPreparer}s as configured in module test config.
+     * @param preparers
+     */
+    void setPackagePreparers(List<ITargetPreparer> preparers) {
+        mPreparers = preparers;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<ITargetPreparer> getPackagePreparers() {
+        return mPreparers;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -240,7 +257,8 @@
             mDigest = generateDigest(testCaseDir, mJarPath);
             return vmHostTest;
         } else if (DEQP_TEST.equals(mTestType)) {
-            DeqpTestRunner deqpTest = new DeqpTestRunner(mAppPackageName, mName, mTests);
+            DeqpTestRunner deqpTest =
+                    new DeqpTestRunner(mAppPackageName, mName, mTests, mTestInstanceArguments);
             deqpTest.setAbi(mAbi);
             return deqpTest;
         } else if (NATIVE_TEST.equals(mTestType)) {
@@ -252,19 +270,6 @@
             WrappedGTest wrappedGeeTest = new WrappedGTest(mAppNameSpace, mAppPackageName, mName, mRunner);
             wrappedGeeTest.setAbi(mAbi);
             return wrappedGeeTest;
-        } else if (ACCESSIBILITY_TEST.equals(mTestType)) {
-            AccessibilityTestRunner test = new AccessibilityTestRunner();
-            return setInstrumentationTest(test, testCaseDir);
-        } else if (PRINT_TEST.equals(mTestType)) {
-            PrintTestRunner test = new PrintTestRunner();
-            return setPrintTest(test, testCaseDir);
-        } else if (ACCESSIBILITY_SERVICE_TEST.equals(mTestType)) {
-            @SuppressWarnings("deprecation")
-            AccessibilityServiceTestRunner test = new AccessibilityServiceTestRunner();
-            return setInstrumentationTest(test, testCaseDir);
-        } else if (DISPLAY_TEST.equals(mTestType)) {
-            DisplayTestRunner test = new DisplayTestRunner();
-            return setInstrumentationTest(test, testCaseDir);
         } else if (UIAUTOMATOR_TEST.equals(mTestType)) {
             UiAutomatorJarTest uiautomatorTest = new UiAutomatorJarTest();
             return setUiAutomatorTest(uiautomatorTest);
@@ -291,19 +296,6 @@
         }
     }
 
-    private PrintTestRunner setPrintTest(PrintTestRunner printTest,
-            File testCaseDir) {
-        printTest.setRunName(mAppPackageName);
-        printTest.setPackageName(mAppNameSpace);
-        printTest.setRunnerName(mRunner);
-        printTest.setTestPackageName(mTestPackageName);
-        printTest.setClassName(mClassName);
-        printTest.setMethodName(mMethodName);
-        printTest.setAbi(mAbi);
-        mDigest = generateDigest(testCaseDir, String.format("%s.apk", mName));
-        return printTest;
-    }
-
     /**
      * Populates given {@link CtsInstrumentationApkTest} with data from the package xml.
      *
@@ -379,6 +371,7 @@
     void addTest(TestIdentifier testDef, int timeout) {
         mTests.add(testDef);
         mTestClasses.add(testDef.getClassName());
+        mTestInstanceArguments.put(testDef, new LinkedList<Map<String, String>>());
         // 0 means no timeout, so keep 0 if already is.
         if ((timeout > mTimeoutInMins) && (mTimeoutInMins != 0)) {
             mTimeoutInMins = timeout;
@@ -386,6 +379,16 @@
     }
 
     /**
+     * Add a test instance to an existing {@link TestIdentifier}.
+     */
+    void addTestInstance(TestIdentifier testDef, Map<String, String> instanceArguments) {
+        if (!mTestInstanceArguments.containsKey(testDef)) {
+            throw new IllegalStateException("test id does not name an existing test");
+        }
+        mTestInstanceArguments.get(testDef).add(instanceArguments);
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -394,6 +397,15 @@
     }
 
     /**
+     * Get the instance argument map for tests.
+     * <p/>
+     * Exposed for unit testing.
+     */
+    public Map<TestIdentifier, List<Map<String, String>>> getTestInstanceArguments() {
+        return mTestInstanceArguments;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -427,8 +439,8 @@
         } catch (IOException e) {
             CLog.e(e);
         } finally {
-            StreamUtil.closeStream(d);
-            StreamUtil.closeStream(fileStream);
+            StreamUtil.close(d);
+            StreamUtil.close(fileStream);
         }
         return "failed to generate digest";
     }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
index aea6613..7e16170 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
@@ -17,6 +17,9 @@
 
 import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfiguration;
 import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
 
 import java.io.BufferedInputStream;
@@ -27,8 +30,8 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -63,22 +66,68 @@
     private void parse(File dir) {
         File[] xmlFiles = dir.listFiles(new XmlFilter());
         for (File xmlFile : xmlFiles) {
-            parseTestFromXml(xmlFile);
+            parseModuleTestConfigs(xmlFile);
         }
     }
 
-    private void parseTestFromXml(File xmlFile)  {
+    /**
+     * Infer package preparer config from package XML definition file and return if exists
+     * @param pkgXml {@link File} instance referencing the package XML definition
+     * @return the matching package preparer if exists, <code>null</code> otherwise
+     */
+    private File getPreparerDefForPackage(File pkgXml) {
+        String fullPath = pkgXml.getAbsolutePath();
+        int lastDot = fullPath.lastIndexOf('.');
+        if (lastDot == -1) {
+            // huh?
+            return null;
+        }
+        File preparer = new File(fullPath.substring(0, lastDot) + ".config");
+        if (preparer.exists()) {
+            return preparer;
+        }
+        return null;
+    }
+
+    /**
+     * Processes test module definition XML file, and stores parsed data structure in class member
+     * variable. Parsed config objects will be associated with each applicable ABI type so multiple
+     * {@link TestPackageDef}s will be generated accordingly. In addition, based on
+     * &lt;module name&gt;.config file naming convention, this method also looks for the optional
+     * module test config, and attaches defined configuration objects to the {@link TestPackageDef}
+     * representing the module accordingly.
+     * @param xmlFile the module definition XML
+     */
+    private void parseModuleTestConfigs(File xmlFile)  {
         TestPackageXmlParser parser = new TestPackageXmlParser(mIncludeKnownFailures);
         try {
             parser.parse(createStreamFromFile(xmlFile));
+            // based on test module XML file path, and the <module name>.config naming convention,
+            // infers the module test config file, and parses it
+            File preparer = getPreparerDefForPackage(xmlFile);
+            IConfiguration config = null;
+            if (preparer != null) {
+                try {
+                    // invokes parser to process the test module config file
+                    config = ConfigurationFactory.getInstance().createConfigurationFromArgs(
+                            new String[]{preparer.getAbsolutePath()});
+                } catch (ConfigurationException e) {
+                    throw new RuntimeException(
+                            String.format("error parsing config file: %s", xmlFile.getName()), e);
+                }
+            }
             Set<TestPackageDef> defs = parser.getTestPackageDefs();
             if (defs.isEmpty()) {
                 Log.w(LOG_TAG, String.format("Could not find test package info in xml file %s",
                         xmlFile.getAbsolutePath()));
             }
+            // loops over multiple package defs defined for each ABI type
             for (TestPackageDef def : defs) {
                 String name = def.getAppPackageName();
                 String abi = def.getAbi().getName();
+                if (config != null) {
+                    def.setPackagePreparers(config.getTargetPreparers());
+                }
                 if (!mTestMap.containsKey(abi)) {
                     mTestMap.put(abi, new HashMap<String, TestPackageDef>());
                 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
index baceb8b..649dd9e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
@@ -59,6 +59,7 @@
      *     <TestSuite ...>
      *        <TestCase>
      *           <Test>
+     *             <TestInstance> (optional)
      */
     private class TestPackageHandler extends DefaultHandler {
 
@@ -66,9 +67,11 @@
         private static final String TEST_SUITE_TAG = "TestSuite";
         private static final String TEST_CASE_TAG = "TestCase";
         private static final String TEST_TAG = "Test";
+        private static final String TEST_INSTANCE_TAG = "TestInstance";
 
         // holds current class name segments
         private Stack<String> mClassNameStack = new Stack<String>();
+        private TestIdentifier mTestId;
 
         @Override
         public void startElement(String uri, String localName, String name, Attributes attributes) {
@@ -139,6 +142,7 @@
                             classNameBuilder.append(".");
                         }
                     }
+                    mTestId = new TestIdentifier(classNameBuilder.toString(), methodName);
                     int timeout = -1;
                     String timeoutStr = attributes.getValue("timeout");
                     if (timeoutStr != null) {
@@ -158,14 +162,24 @@
                             }
                         }
                         for (String abi : abis) {
-                            TestIdentifier testId = new TestIdentifier(
-                                    classNameBuilder.toString(), methodName);
-                            mPackageDefs.get(abi).addTest(testId, timeout);
+                            mPackageDefs.get(abi).addTest(mTestId, timeout);
                         }
                     }
                 }
+            } else if (TEST_INSTANCE_TAG.equals(localName)) {
+                if (mTestId != null) {
+                    final Map<String, String> instanceArguments = genAttributeMap(attributes);
+                    for (TestPackageDef packageDef : mPackageDefs.values()) {
+                        if (packageDef.getTests().contains(mTestId)) {
+                            packageDef.addTestInstance(mTestId, instanceArguments);
+                        }
+                    }
+                } else {
+                    Log.e(LOG_TAG, String.format(
+                            "Invalid XML: encountered a '%s' tag not enclosed within a '%s' tag",
+                            TEST_INSTANCE_TAG, TEST_TAG));
+                }
             }
-
         }
 
         private String getTestType(Attributes attributes) {
@@ -182,6 +196,8 @@
         public void endElement (String uri, String localName, String qName) {
             if (TEST_SUITE_TAG.equals(localName) || TEST_CASE_TAG.equals(localName)) {
                 mClassNameStack.pop();
+            } else if (TEST_TAG.equals(localName)) {
+                mTestId = null;
             }
         }
 
@@ -192,6 +208,19 @@
             return stringValue != null &&
                     Boolean.parseBoolean(stringValue);
         }
+
+        private Map<String, String> genAttributeMap(Attributes attributes) {
+            final Map<String, String> attribMap = new HashMap<String, String>();
+            for (int i = 0; i < attributes.getLength(); ++i) {
+                final String localName = attributes.getLocalName(i);
+                final String namespace = attributes.getURI(i);
+                final String fullyQualifiedName =
+                        (namespace.isEmpty()) ? (localName) : (namespace + ":" + localName);
+
+                attribMap.put(fullyQualifiedName, attributes.getValue(i));
+            }
+            return attribMap;
+        }
     }
 
     @Override
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
index ad1430e..29c1324 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
@@ -25,6 +25,7 @@
 import com.android.cts.tradefed.testtype.Abi;
 import com.android.cts.tradefed.testtype.CtsTestTest;
 import com.android.cts.tradefed.testtype.DeqpTestRunnerTest;
+import com.android.cts.tradefed.testtype.GeeTestTest;
 import com.android.cts.tradefed.testtype.JarHostTestTest;
 import com.android.cts.tradefed.testtype.TestFilterTest;
 import com.android.cts.tradefed.testtype.TestPackageDefTest;
@@ -60,13 +61,14 @@
 
         // testtype package
         addTestSuite(CtsTestTest.class);
+        addTestSuite(DeqpTestRunnerTest.class);
+        addTestSuite(GeeTestTest.class);
         addTestSuite(JarHostTestTest.class);
         addTestSuite(TestFilterTest.class);
         addTestSuite(TestPackageDefTest.class);
         addTestSuite(TestPackageXmlParserTest.class);
         addTestSuite(TestPlanTest.class);
         addTestSuite(WrappedGTestResultParserTest.class);
-        addTestSuite(DeqpTestRunnerTest.class);
     }
 
     public static Test suite() {
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
index 30e2ba8..5dc2e5a 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
@@ -34,6 +34,7 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -377,6 +378,34 @@
         }
     }
 
+    /**
+     * Test {@link CtsTestTest#join} works.
+     * @throws DeviceNotAvailableException
+     */
+    public void testJoin() throws DeviceNotAvailableException {
+        String expected = "a@b@c";
+        String actual = mCtsTest.join(new ArrayList<String>(Arrays.asList("a", "b", "c")), "@");
+        assertEquals(expected, actual);
+    }
+
+    /**
+     * Test {@link CtsTestTest#join} for a single element list.
+     * @throws DeviceNotAvailableException
+     */
+    public void testSingleJoin() throws DeviceNotAvailableException {
+        String actual = mCtsTest.join(new ArrayList<String>(Arrays.asList("foo")), "@");
+        assertEquals("foo", actual);
+    }
+
+    /**
+     * Test {@link CtsTestTest#join} for an empty list.
+     * @throws DeviceNotAvailableException
+     */
+    public void testEmptyJoin() throws DeviceNotAvailableException {
+        String actual = mCtsTest.join(new ArrayList<String>(), "@");
+        assertEquals("", actual);
+    }
+
     private void replayMocks(Object... mocks) {
         EasyMock.replay(mMockRepo, mMockPlan, mMockDevice, mMockPackageDef, mMockListener, mMockTest);
         EasyMock.replay(mocks);
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
index c41793f..f770261 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
@@ -21,6 +21,7 @@
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.testrunner.ITestRunListener;
 import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.testtype.IAbi;
@@ -32,7 +33,10 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -45,8 +49,23 @@
     private static final String LOG_FILE_NAME = "/sdcard/TestLog.qpa";
     private static final String INSTRUMENTATION_NAME =
             "com.drawelements.deqp/com.drawelements.deqp.testercore.DeqpInstrumentation";
+    private static final String QUERY_INSTRUMENTATION_NAME =
+            "com.drawelements.deqp/com.drawelements.deqp.platformutil.DeqpPlatformCapabilityQueryInstrumentation";
     private static final String DEQP_ONDEVICE_APK = "com.drawelements.deqp.apk";
     private static final String DEQP_ONDEVICE_PKG = "com.drawelements.deqp";
+    private static final String ONLY_LANDSCAPE_FEATURES =
+            "feature:"+DeqpTestRunner.FEATURE_LANDSCAPE;
+    private static final String ALL_FEATURES =
+            ONLY_LANDSCAPE_FEATURES + "\nfeature:"+DeqpTestRunner.FEATURE_PORTRAIT;
+    private static List<Map<String,String>> DEFAULT_INSTANCE_ARGS;
+
+    static {
+        DEFAULT_INSTANCE_ARGS = new ArrayList<>(1);
+        DEFAULT_INSTANCE_ARGS.add(new HashMap<String,String>());
+        DEFAULT_INSTANCE_ARGS.iterator().next().put("glconfig", "rgba8888d24s8");
+        DEFAULT_INSTANCE_ARGS.iterator().next().put("rotation", "unspecified");
+        DEFAULT_INSTANCE_ARGS.iterator().next().put("surfacetype", "window");
+    }
 
     /**
      * {@inheritDoc}
@@ -106,13 +125,15 @@
         ITestInvocationListener mockListener
                 = EasyMock.createStrictMock(ITestInvocationListener.class);
         Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
-
         tests.add(testId);
 
+        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
+        instance.put(testId, DEFAULT_INSTANCE_ARGS);
+
         DeqpTestRunner deqpTest = new DeqpTestRunner(NAME,
                 "dEQP-GLES" + Integer.toString(requiredMajorVersion)
                 + (requiredMinorVersion > 0 ? Integer.toString(requiredMinorVersion) : ""),
-                tests);
+                tests, instance);
         deqpTest.setAbi(UnitTests.ABI);
 
         int version = (majorVersion << 16) | minorVersion;
@@ -129,6 +150,8 @@
                     EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName()))))
                     .andReturn(null).once();
 
+            expectRenderConfigQuery(mockDevice, requiredMajorVersion, requiredMinorVersion);
+
             EasyMock.expect(mockDevice.executeShellCommand(
                     EasyMock.eq("rm " + CASE_LIST_FILE_NAME))).andReturn("").once();
 
@@ -140,7 +163,10 @@
 
             String command = String.format(
                     "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
-                        + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8\" "
+                        + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8 "
+                        + "--deqp-screen-rotation=unspecified "
+                        + "--deqp-surface-type=window "
+                        + "--deqp-log-images=disable\" "
                         + "-e deqpLogData \"%s\" %s",
                     AbiUtils.createAbiFlag(UnitTests.ABI.getName()), LOG_FILE_NAME,
                     CASE_LIST_FILE_NAME, false, INSTRUMENTATION_NAME);
@@ -188,6 +214,46 @@
         EasyMock.verify(mockDevice);
     }
 
+    private void expectRenderConfigQuery(ITestDevice mockDevice, int majorVersion, int minorVersion)
+            throws Exception {
+        expectRenderConfigQuery(mockDevice, String.format("--deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=%d "
+                + "--deqp-gl-minor-version=%d", majorVersion, minorVersion));
+    }
+
+    private void expectRenderConfigQuery(ITestDevice mockDevice, String commandLine)
+            throws Exception {
+        expectRenderConfigQueryAndReturn(mockDevice, commandLine, "Yes");
+    }
+
+    private void expectRenderConfigQueryAndReturn(ITestDevice mockDevice, String commandLine,
+            String output) throws Exception {
+        final String queryOutput = "INSTRUMENTATION_RESULT: Supported=" + output + "\r\n"
+                + "INSTRUMENTATION_CODE: 0\r\n";
+        final String command = String.format(
+                "am instrument %s -w -e deqpQueryType renderConfigSupported -e deqpCmdLine "
+                    + "\"%s\" %s",
+                AbiUtils.createAbiFlag(UnitTests.ABI.getName()), commandLine, QUERY_INSTRUMENTATION_NAME);
+
+        mockDevice.executeShellCommand(EasyMock.eq(command),
+                EasyMock.<IShellOutputReceiver>notNull());
+
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            @Override
+            public Object answer() {
+                IShellOutputReceiver receiver
+                        = (IShellOutputReceiver)EasyMock.getCurrentArguments()[1];
+
+                receiver.addOutput(queryOutput.getBytes(), 0, queryOutput.length());
+                receiver.flush();
+
+                return null;
+            }
+        });
+    }
+
     /**
      * Test that result code produces correctly pass or fail.
      */
@@ -228,10 +294,12 @@
         ITestInvocationListener mockListener
                 = EasyMock.createStrictMock(ITestInvocationListener.class);
         Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
-
         tests.add(testId);
 
-        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests);
+        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
+        instance.put(testId, DEFAULT_INSTANCE_ARGS);
+
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
         deqpTest.setAbi(UnitTests.ABI);
 
         int version = 3 << 16;
@@ -245,6 +313,8 @@
                 EasyMock.eq(true), EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName()))))
                 .andReturn(null).once();
 
+        expectRenderConfigQuery(mockDevice, 3, 0);
+
         EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
                 .andReturn("").once();
 
@@ -256,7 +326,10 @@
 
         String command = String.format(
                 "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
-                    + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8\" "
+                    + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8 "
+                    + "--deqp-screen-rotation=unspecified "
+                    + "--deqp-surface-type=window "
+                    + "--deqp-log-images=disable\" "
                     + "-e deqpLogData \"%s\" %s",
                 AbiUtils.createAbiFlag(UnitTests.ABI.getName()), LOG_FILE_NAME,
                 CASE_LIST_FILE_NAME, false, INSTRUMENTATION_NAME);
@@ -285,7 +358,8 @@
 
         if (!pass) {
             mockListener.testFailed(testId,
-                    resultCode + ": Detail" + resultCode);
+                    "=== with config {glformat=rgba8888d24s8,rotation=unspecified,surfacetype=window} ===\n"
+                    + resultCode + ": Detail" + resultCode);
 
             EasyMock.expectLastCall().once();
         }
@@ -412,12 +486,14 @@
         ITestInvocationListener mockListener
                 = EasyMock.createStrictMock(ITestInvocationListener.class);
         Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+        Map<TestIdentifier, List<Map<String, String>>> instances = new HashMap<>();
 
         for (TestIdentifier id : testIds) {
             tests.add(id);
+            instances.put(id, DEFAULT_INSTANCE_ARGS);
         }
 
-        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests);
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instances);
         deqpTest.setAbi(UnitTests.ABI);
 
         int version = 3 << 16;
@@ -430,6 +506,8 @@
                 EasyMock.eq(true), EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName()))))
                 .andReturn(null).once();
 
+        expectRenderConfigQuery(mockDevice, 3, 0);
+
         EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
                 .andReturn("").once();
 
@@ -441,7 +519,10 @@
 
         String command = String.format(
                 "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
-                    + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8\" "
+                    + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8 "
+                    + "--deqp-screen-rotation=unspecified "
+                    + "--deqp-surface-type=window "
+                    + "--deqp-log-images=disable\" "
                     + "-e deqpLogData \"%s\" %s",
                 AbiUtils.createAbiFlag(UnitTests.ABI.getName()), LOG_FILE_NAME,
                 CASE_LIST_FILE_NAME, false, INSTRUMENTATION_NAME);
@@ -493,6 +574,270 @@
     }
 
     /**
+     * Test that test are left unexecuted if pm list query fails
+     */
+    public void testRun_queryPmListFailure()
+            throws Exception {
+        final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.orientation", "test");
+
+        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
+        ITestInvocationListener mockListener
+                = EasyMock.createStrictMock(ITestInvocationListener.class);
+        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+        tests.add(testId);
+
+        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
+        instance.put(testId, new ArrayList<Map<String,String>>(1));
+        instance.get(testId).add(new HashMap<String,String>());
+        instance.get(testId).iterator().next().put("glconfig", "rgba8888d24s8");
+        instance.get(testId).iterator().next().put("rotation", "90");
+        instance.get(testId).iterator().next().put("surfacetype", "window");
+
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
+        deqpTest.setAbi(UnitTests.ABI);
+        deqpTest.setDevice(mockDevice);
+        deqpTest.setBuildHelper(new StubCtsBuildHelper());
+
+        int version = 3 << 16;
+        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+                .andReturn(Integer.toString(version)).atLeastOnce();
+
+        EasyMock.expect(mockDevice.executeShellCommand("pm list features"))
+                .andReturn("not a valid format");
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+            andReturn("").once();
+
+        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+                EasyMock.eq(true),
+                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+                .once();
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+                .andReturn("").once();
+
+        mockListener.testRunStarted(ID, 1);
+        EasyMock.expectLastCall().once();
+
+        mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        EasyMock.replay(mockDevice);
+        EasyMock.replay(mockListener);
+        deqpTest.run(mockListener);
+        EasyMock.verify(mockListener);
+        EasyMock.verify(mockDevice);
+    }
+
+    /**
+     * Test that test are left unexecuted if renderablity query fails
+     */
+    public void testRun_queryRenderabilityFailure()
+            throws Exception {
+        final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.orientation", "test");
+
+        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
+        ITestInvocationListener mockListener
+                = EasyMock.createStrictMock(ITestInvocationListener.class);
+        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+        tests.add(testId);
+
+        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
+        instance.put(testId, new ArrayList<Map<String,String>>(1));
+        instance.get(testId).add(new HashMap<String,String>());
+        instance.get(testId).iterator().next().put("glconfig", "rgba8888d24s8");
+        instance.get(testId).iterator().next().put("rotation", "unspecified");
+        instance.get(testId).iterator().next().put("surfacetype", "window");
+
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
+        deqpTest.setAbi(UnitTests.ABI);
+        deqpTest.setDevice(mockDevice);
+        deqpTest.setBuildHelper(new StubCtsBuildHelper());
+
+        int version = 3 << 16;
+        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+                .andReturn(Integer.toString(version)).atLeastOnce();
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+            andReturn("").once();
+
+        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+                EasyMock.eq(true),
+                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+                .once();
+
+        expectRenderConfigQueryAndReturn(mockDevice,
+                "--deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", "Maybe?");
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+                .andReturn("").once();
+
+        mockListener.testRunStarted(ID, 1);
+        EasyMock.expectLastCall().once();
+
+        mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        EasyMock.replay(mockDevice);
+        EasyMock.replay(mockListener);
+        deqpTest.run(mockListener);
+        EasyMock.verify(mockListener);
+        EasyMock.verify(mockDevice);
+    }
+
+    /**
+     * Test that orientation is supplied to runner correctly
+     */
+    private void testOrientation(final String rotation, final String featureString)
+            throws Exception {
+        final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.orientation", "test");
+        final String testPath = "dEQP-GLES3.orientation.test";
+        final String testTrie = "{dEQP-GLES3{orientation{test}}}";
+        final String output = "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=" + testPath + "\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_CODE: 0\r\n";
+
+        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
+        ITestInvocationListener mockListener
+                = EasyMock.createStrictMock(ITestInvocationListener.class);
+        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+        tests.add(testId);
+
+        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
+        instance.put(testId, new ArrayList<Map<String,String>>(1));
+        instance.get(testId).add(new HashMap<String,String>());
+        instance.get(testId).iterator().next().put("glconfig", "rgba8888d24s8");
+        instance.get(testId).iterator().next().put("rotation", rotation);
+        instance.get(testId).iterator().next().put("surfacetype", "window");
+
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
+        deqpTest.setAbi(UnitTests.ABI);
+        deqpTest.setDevice(mockDevice);
+        deqpTest.setBuildHelper(new StubCtsBuildHelper());
+
+        int version = 3 << 16;
+        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+                .andReturn(Integer.toString(version)).atLeastOnce();
+
+        if (!rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_UNSPECIFIED)) {
+            EasyMock.expect(mockDevice.executeShellCommand("pm list features"))
+                    .andReturn(featureString);
+        }
+
+        final boolean isPortraitOrientation =
+                rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_PORTRAIT) ||
+                rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_REVERSE_PORTRAIT);
+        final boolean isLandscapeOrientation =
+                rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_LANDSCAPE) ||
+                rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_REVERSE_LANDSCAPE);
+        final boolean executable =
+                rotation.equals(DeqpTestRunner.BatchRunConfiguration.ROTATION_UNSPECIFIED) ||
+                (isPortraitOrientation &&
+                featureString.contains(DeqpTestRunner.FEATURE_PORTRAIT)) ||
+                (isLandscapeOrientation &&
+                featureString.contains(DeqpTestRunner.FEATURE_LANDSCAPE));
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+            andReturn("").once();
+
+        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+                EasyMock.eq(true),
+                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+                .once();
+
+        if (executable) {
+            expectRenderConfigQuery(mockDevice, String.format(
+                    "--deqp-gl-config-name=rgba8888d24s8 --deqp-screen-rotation=%s "
+                    + "--deqp-surface-type=window --deqp-gl-major-version=3 "
+                    + "--deqp-gl-minor-version=0", rotation));
+
+            EasyMock.expect(
+                    mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
+                    .andReturn("").once();
+
+            EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
+                    .andReturn("").once();
+
+            EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
+                    .andReturn(true).once();
+
+            String command = String.format(
+                    "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
+                        + "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8 "
+                        + "--deqp-screen-rotation=%s "
+                        + "--deqp-surface-type=window "
+                        + "--deqp-log-images=disable\" "
+                        + "-e deqpLogData \"%s\" %s",
+                    AbiUtils.createAbiFlag(UnitTests.ABI.getName()), LOG_FILE_NAME,
+                    CASE_LIST_FILE_NAME, rotation, false, INSTRUMENTATION_NAME);
+
+            mockDevice.executeShellCommand(EasyMock.eq(command),
+                    EasyMock.<IShellOutputReceiver>notNull());
+
+            EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+                @Override
+                public Object answer() {
+                    IShellOutputReceiver receiver
+                            = (IShellOutputReceiver)EasyMock.getCurrentArguments()[1];
+
+                    receiver.addOutput(output.getBytes(), 0, output.length());
+                    receiver.flush();
+
+                    return null;
+                }
+            });
+        }
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+                .andReturn("").once();
+
+        mockListener.testRunStarted(ID, 1);
+        EasyMock.expectLastCall().once();
+
+        mockListener.testStarted(EasyMock.eq(testId));
+        EasyMock.expectLastCall().once();
+
+        mockListener.testEnded(EasyMock.eq(testId), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        EasyMock.replay(mockDevice);
+        EasyMock.replay(mockListener);
+        deqpTest.run(mockListener);
+        EasyMock.verify(mockListener);
+        EasyMock.verify(mockDevice);
+    }
+
+    /**
      * Test OpeGL ES3 tests on device with OpenGL ES2.
      */
     public void testRun_require30DeviceVersion20() throws Exception {
@@ -596,4 +941,686 @@
     public void testRun_resultTimeout() throws Exception {
         testResultCode("Timeout", false);
     }
+    /**
+     * Test dEQP Orientation
+     */
+    public void testRun_orientationLandscape() throws Exception {
+        testOrientation("90", ALL_FEATURES);
+    }
+
+    /**
+     * Test dEQP Orientation
+     */
+    public void testRun_orientationPortrait() throws Exception {
+        testOrientation("0", ALL_FEATURES);
+    }
+
+    /**
+     * Test dEQP Orientation
+     */
+    public void testRun_orientationReverseLandscape() throws Exception {
+        testOrientation("270", ALL_FEATURES);
+    }
+
+    /**
+     * Test dEQP Orientation
+     */
+    public void testRun_orientationReversePortrait() throws Exception {
+        testOrientation("180", ALL_FEATURES);
+    }
+
+    /**
+     * Test dEQP Orientation
+     */
+    public void testRun_orientationUnspecified() throws Exception {
+        testOrientation("unspecified", ALL_FEATURES);
+    }
+
+    /**
+     * Test dEQP Orientation with limited features
+     */
+    public void testRun_orientationUnspecifiedLimitedFeatures() throws Exception {
+        testOrientation("unspecified", ONLY_LANDSCAPE_FEATURES);
+    }
+
+    /**
+     * Test dEQP Orientation with limited features
+     */
+    public void testRun_orientationLandscapeLimitedFeatures() throws Exception {
+        testOrientation("90", ONLY_LANDSCAPE_FEATURES);
+    }
+
+    /**
+     * Test dEQP Orientation with limited features
+     */
+    public void testRun_orientationPortraitLimitedFeatures() throws Exception {
+        testOrientation("0", ONLY_LANDSCAPE_FEATURES);
+    }
+
+    /**
+     * Test dEQP unsupported pixel format
+     */
+    public void testRun_unsupportedPixelFormat() throws Exception {
+        final String pixelFormat = "rgba5658d16m4";
+        final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.pixelformat", "test");
+        final String testPath = "dEQP-GLES3.pixelformat.test";
+        final String testTrie = "{dEQP-GLES3{pixelformat{test}}}";
+        final String output = "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=" + testPath + "\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_CODE: 0\r\n";
+
+        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
+        ITestInvocationListener mockListener
+                = EasyMock.createStrictMock(ITestInvocationListener.class);
+        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+        tests.add(testId);
+
+        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
+        instance.put(testId, new ArrayList<Map<String,String>>(1));
+        instance.get(testId).add(new HashMap<String,String>());
+        instance.get(testId).iterator().next().put("glconfig", pixelFormat);
+        instance.get(testId).iterator().next().put("rotation", "unspecified");
+        instance.get(testId).iterator().next().put("surfacetype", "window");
+
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
+        deqpTest.setAbi(UnitTests.ABI);
+        deqpTest.setDevice(mockDevice);
+        deqpTest.setBuildHelper(new StubCtsBuildHelper());
+
+        int version = 3 << 16;
+        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+                .andReturn(Integer.toString(version)).atLeastOnce();
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+            andReturn("").once();
+
+        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+                EasyMock.eq(true),
+                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+                .once();
+
+        expectRenderConfigQueryAndReturn(mockDevice, String.format(
+                "--deqp-gl-config-name=%s --deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", pixelFormat), "No");
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+                .andReturn("").once();
+
+        mockListener.testRunStarted(ID, 1);
+        EasyMock.expectLastCall().once();
+
+        mockListener.testStarted(EasyMock.eq(testId));
+        EasyMock.expectLastCall().once();
+
+        mockListener.testEnded(EasyMock.eq(testId), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        EasyMock.replay(mockDevice);
+        EasyMock.replay(mockListener);
+        deqpTest.run(mockListener);
+        EasyMock.verify(mockListener);
+        EasyMock.verify(mockDevice);
+    }
+
+    /**
+     * Test dEQP with multiple instances
+     */
+    public void testRun_multipleInstances() throws Exception {
+        final String instrumentationAnswerConfigA =
+                "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.passall\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.failone\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.crashtwo\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"; // early eof
+        final String instrumentationAnswerConfigB =
+                "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.passall\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.crashtwo\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TerminateTestCase-Reason=Magic\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TerminateTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.skipone\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_CODE: 0\r\n";
+        final String instrumentationAnswerConfigC =
+                "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.failone\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Fail\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Fail\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.crashtwo\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_CODE: 0\r\n";
+
+        final TestIdentifier[] testIds = {
+                new TestIdentifier("dEQP-GLES3.instances", "passall"),
+                new TestIdentifier("dEQP-GLES3.instances", "failone"),
+                new TestIdentifier("dEQP-GLES3.instances", "crashtwo"),
+                new TestIdentifier("dEQP-GLES3.instances", "skipone"),
+        };
+
+        final String[] testPaths = {
+                "dEQP-GLES3.instances.passall",
+                "dEQP-GLES3.instances.failone",
+                "dEQP-GLES3.instances.crashtwo",
+                "dEQP-GLES3.instances.skipone",
+        };
+
+        Map<String,String> supportedConfigA = new HashMap<>();
+        supportedConfigA.put("glconfig", "rgba8888d24s8");
+        supportedConfigA.put("rotation", "unspecified");
+        supportedConfigA.put("surfacetype", "window");
+
+        Map<String,String> supportedConfigB = new HashMap<>();
+        supportedConfigB.put("glconfig", "rgba8888d24s8");
+        supportedConfigB.put("rotation", "90");
+        supportedConfigB.put("surfacetype", "window");
+
+        Map<String,String> supportedConfigC = new HashMap<>();
+        supportedConfigC.put("glconfig", "rgba8888d24s8");
+        supportedConfigC.put("rotation", "180");
+        supportedConfigC.put("surfacetype", "window");
+
+        Map<String,String> unsupportedConfig = new HashMap<>();
+        unsupportedConfig.put("glconfig", "rgb565d16s0");
+        unsupportedConfig.put("rotation", "unspecified");
+        unsupportedConfig.put("surfacetype", "window");
+
+        Map<TestIdentifier, List<Map<String, String>>> instances = new HashMap<>();
+
+        // pass all
+        instances.put(testIds[0], new ArrayList<Map<String,String>>());
+        instances.get(testIds[0]).add(supportedConfigA);
+        instances.get(testIds[0]).add(supportedConfigB);
+
+        // fail one
+        instances.put(testIds[1], new ArrayList<Map<String,String>>());
+        instances.get(testIds[1]).add(supportedConfigA);
+        instances.get(testIds[1]).add(supportedConfigC);
+
+        // crash two
+        instances.put(testIds[2], new ArrayList<Map<String,String>>());
+        instances.get(testIds[2]).add(supportedConfigA);
+        instances.get(testIds[2]).add(supportedConfigC);
+        instances.get(testIds[2]).add(supportedConfigB);
+
+        // skip one
+        instances.put(testIds[3], new ArrayList<Map<String,String>>());
+        instances.get(testIds[3]).add(supportedConfigB);
+        instances.get(testIds[3]).add(unsupportedConfig);
+
+        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+        for (TestIdentifier id : testIds) {
+            tests.add(id);
+        }
+
+        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
+        ITestInvocationListener mockListener
+                = EasyMock.createStrictMock(ITestInvocationListener.class);
+
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instances);
+        deqpTest.setAbi(UnitTests.ABI);
+        deqpTest.setDevice(mockDevice);
+        deqpTest.setBuildHelper(new StubCtsBuildHelper());
+
+        int version = 3 << 16;
+        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+                .andReturn(Integer.toString(version)).atLeastOnce();
+        EasyMock.expect(mockDevice.executeShellCommand("pm list features")).andReturn(ALL_FEATURES)
+                .anyTimes();
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+            andReturn("").once();
+
+        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+                EasyMock.eq(true),
+                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+                .once();
+
+        // query config A
+        expectRenderConfigQueryAndReturn(mockDevice, "--deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", "Yes");
+
+        // run config A
+        runInstrumentationLineAndAnswer(mockDevice,
+                "{dEQP-GLES3{instances{passall,failone,crashtwo}}}",
+                "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+                + " --deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-log-images=disable", instrumentationAnswerConfigA);
+
+        // query for config B
+        expectRenderConfigQueryAndReturn(mockDevice, "--deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=90 "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", "Yes");
+
+        // run for config B
+        runInstrumentationLineAndAnswer(mockDevice,
+                "{dEQP-GLES3{instances{passall,crashtwo,skipone}}}",
+                "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+                + " --deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=90 "
+                + "--deqp-surface-type=window "
+                + "--deqp-log-images=disable", instrumentationAnswerConfigB);
+
+        // query for config C
+        expectRenderConfigQueryAndReturn(mockDevice, "--deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=180 "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", "Yes");
+
+        // run for config C
+        runInstrumentationLineAndAnswer(mockDevice,
+                "{dEQP-GLES3{instances{failone,crashtwo}}}",
+                "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+                + " --deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=180 "
+                + "--deqp-surface-type=window "
+                + "--deqp-log-images=disable" , instrumentationAnswerConfigC);
+
+        // query for unsupported config
+        expectRenderConfigQueryAndReturn(mockDevice, "--deqp-gl-config-name=rgb565d16s0 "
+                + "--deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", "No");
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+                .andReturn("").once();
+
+        mockListener.testRunStarted(ID, 4);
+        EasyMock.expectLastCall().once();
+
+        // pass all
+        mockListener.testStarted(EasyMock.eq(testIds[0]));
+        EasyMock.expectLastCall().once();
+
+        mockListener.testEnded(EasyMock.eq(testIds[0]), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        // fail one
+        mockListener.testStarted(EasyMock.eq(testIds[1]));
+        EasyMock.expectLastCall().once();
+
+        mockListener.testFailed(testIds[1],
+                "=== with config {glformat=rgba8888d24s8,rotation=180,surfacetype=window} ===\n"
+                + "Fail: Fail");
+        EasyMock.expectLastCall().once();
+
+        mockListener.testEnded(EasyMock.eq(testIds[1]), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        // crash two
+        mockListener.testStarted(EasyMock.eq(testIds[2]));
+        EasyMock.expectLastCall().once();
+
+        mockListener.testFailed(testIds[2],
+                "=== with config {glformat=rgba8888d24s8,rotation=unspecified,surfacetype=window} ===\n"
+                + "Crash: Incomplete test log\n"
+                + "=== with config {glformat=rgba8888d24s8,rotation=90,surfacetype=window} ===\n"
+                + "Terminated: Magic");
+        EasyMock.expectLastCall().once();
+
+        mockListener.testEnded(EasyMock.eq(testIds[2]), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        // skip one
+        mockListener.testStarted(EasyMock.eq(testIds[3]));
+        EasyMock.expectLastCall().once();
+
+        mockListener.testEnded(EasyMock.eq(testIds[3]), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        EasyMock.replay(mockDevice);
+        EasyMock.replay(mockListener);
+        deqpTest.run(mockListener);
+        EasyMock.verify(mockListener);
+        EasyMock.verify(mockDevice);
+    }
+
+    /**
+     * Test dEQP with runner if device is lost during one of multiple instances.
+     */
+    public void testRun_multipleInstancesLossOfDeviceMidInstance() throws Exception {
+        final String instrumentationAnswerFine =
+                "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.loss.instance\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_CODE: 0\r\n";
+        final String instrumentationAnswerCrash =
+                "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.loss.instance\r\n"
+                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"; // early <EOF>
+
+        final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.loss", "instance");
+        final String testPath = "dEQP-GLES3.loss.instance";
+
+        Map<String,String> supportedConfigA = new HashMap<>();
+        supportedConfigA.put("glconfig", "rgba8888d24s8");
+        supportedConfigA.put("rotation", "unspecified");
+        supportedConfigA.put("surfacetype", "window");
+
+        Map<String,String> supportedConfigB = new HashMap<>();
+        supportedConfigB.put("glconfig", "rgba8888d24s8");
+        supportedConfigB.put("rotation", "90");
+        supportedConfigB.put("surfacetype", "window");
+
+        Map<String,String> supportedConfigC = new HashMap<>();
+        supportedConfigC.put("glconfig", "rgba8888d24s8");
+        supportedConfigC.put("rotation", "180");
+        supportedConfigC.put("surfacetype", "window");
+
+        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+        tests.add(testId);
+
+        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
+        instance.put(testId, new ArrayList<Map<String,String>>());
+        instance.get(testId).add(supportedConfigA);
+        instance.get(testId).add(supportedConfigB);
+        instance.get(testId).add(supportedConfigC);
+
+        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
+        ITestInvocationListener mockListener
+                = EasyMock.createStrictMock(ITestInvocationListener.class);
+
+        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
+        deqpTest.setAbi(UnitTests.ABI);
+        deqpTest.setDevice(mockDevice);
+        deqpTest.setBuildHelper(new StubCtsBuildHelper());
+
+        int version = 3 << 16;
+        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+                .andReturn(Integer.toString(version)).atLeastOnce();
+        EasyMock.expect(mockDevice.executeShellCommand("pm list features")).andReturn(ALL_FEATURES)
+                .anyTimes();
+
+        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+            andReturn("").once();
+
+        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+                EasyMock.eq(true),
+                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+                .once();
+
+        // query config A
+        expectRenderConfigQueryAndReturn(mockDevice, "--deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", "Yes");
+
+        // run config A
+        runInstrumentationLineAndAnswer(mockDevice,
+                "{dEQP-GLES3{loss{instance}}}",
+                "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+                + " --deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=unspecified "
+                + "--deqp-surface-type=window "
+                + "--deqp-log-images=disable", instrumentationAnswerFine);
+
+        // query config B
+        expectRenderConfigQueryAndReturn(mockDevice, "--deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=90 "
+                + "--deqp-surface-type=window "
+                + "--deqp-gl-major-version=3 "
+                + "--deqp-gl-minor-version=0", "Yes");
+
+        // run config B
+        EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
+                .andReturn("").once();
+
+        EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
+                .andReturn("").once();
+
+        EasyMock.expect(mockDevice.pushString("{dEQP-GLES3{loss{instance}}}\n", CASE_LIST_FILE_NAME))
+                .andReturn(true).once();
+
+        String command = String.format(
+                "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
+                + "--deqp-caselist-file=%s"
+                + " --deqp-gl-config-name=rgba8888d24s8 "
+                + "--deqp-screen-rotation=90 "
+                + "--deqp-surface-type=window "
+                + "--deqp-log-images=disable\" "
+                + "-e deqpLogData \"%s\" %s",
+                AbiUtils.createAbiFlag(UnitTests.ABI.getName()), LOG_FILE_NAME,
+                CASE_LIST_FILE_NAME, false, INSTRUMENTATION_NAME);
+
+        mockDevice.executeShellCommand(EasyMock.eq(command),
+                EasyMock.<IShellOutputReceiver>notNull());
+
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            @Override
+            public Object answer() throws DeviceNotAvailableException {
+                IShellOutputReceiver receiver
+                        = (IShellOutputReceiver)EasyMock.getCurrentArguments()[1];
+
+                receiver.addOutput(instrumentationAnswerCrash.getBytes(), 0,
+                        instrumentationAnswerCrash.length());
+                throw new DeviceNotAvailableException();
+            }
+        });
+
+        mockListener.testRunStarted(ID, 1);
+        EasyMock.expectLastCall().once();
+
+        mockListener.testStarted(EasyMock.eq(testId));
+        EasyMock.expectLastCall().once();
+
+        mockListener.testFailed(testId,
+                "=== with config {glformat=rgba8888d24s8,rotation=90,surfacetype=window} ===\n"
+                + "Crash: Device lost");
+        EasyMock.expectLastCall().once();
+
+        mockListener.testEnded(EasyMock.eq(testId), EasyMock.<Map<String, String>>notNull());
+        EasyMock.expectLastCall().once();
+
+        EasyMock.replay(mockDevice);
+        EasyMock.replay(mockListener);
+
+        try {
+            deqpTest.run(mockListener);
+            fail("did not get DeviceNotAvailableException");
+        } catch (DeviceNotAvailableException ex) {
+            // expected
+        }
+
+        EasyMock.verify(mockListener);
+        EasyMock.verify(mockDevice);
+    }
+
+    private void runInstrumentationLineAndAnswer(ITestDevice mockDevice, final String testTrie,
+            final String cmd, final String output) throws Exception {
+        EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
+                .andReturn("").once();
+
+        EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
+                .andReturn("").once();
+
+        EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
+                .andReturn(true).once();
+
+        String command = String.format(
+                "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \"%s\" "
+                    + "-e deqpLogData \"%s\" %s",
+                AbiUtils.createAbiFlag(UnitTests.ABI.getName()), LOG_FILE_NAME,
+                cmd, false, INSTRUMENTATION_NAME);
+
+        mockDevice.executeShellCommand(EasyMock.eq(command),
+                EasyMock.<IShellOutputReceiver>notNull());
+
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            @Override
+            public Object answer() {
+                IShellOutputReceiver receiver
+                        = (IShellOutputReceiver)EasyMock.getCurrentArguments()[1];
+
+                receiver.addOutput(output.getBytes(), 0, output.length());
+                receiver.flush();
+
+                return null;
+            }
+        });
+    }
 }
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/GeeTestTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/GeeTestTest.java
new file mode 100644
index 0000000..93272be
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/GeeTestTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.tradefed.testtype;
+
+import com.android.cts.tradefed.UnitTests;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link GeeTest}.
+ */
+public class GeeTestTest extends TestCase {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+     /**
+     * Test {@link GeeTestTest#getGTestFilters}
+     * @throws DeviceNotAvailableException
+     */
+    public void testGetGTestFilters() {
+        GeeTest test = new GeeTest("package_foo", "exe_foo");
+        test.setPositiveFilters("a");
+        test.setNegativeFilters("b");
+        String actual = test.getGTestFilters();
+        assertEquals("--gtest_filter=a:-b", actual);
+    }
+
+    /**
+     * Test {@link GeeTestTest#getGTestFilters} with only positive filters
+     * @throws DeviceNotAvailableException
+     */
+    public void testGetGTestFiltersPositiveOnly() {
+        GeeTest test = new GeeTest("package_foo", "exe_foo");
+        test.setPositiveFilters("a");
+        String actual = test.getGTestFilters();
+        assertEquals("--gtest_filter=a", actual);
+    }
+
+    /**
+     * Test {@link GeeTestTest#getGTestFilters} with only negative filters
+     * @throws DeviceNotAvailableException
+     */
+    public void testGetGTestFiltersNegativeOnly() {
+        GeeTest test = new GeeTest("package_foo", "exe_foo");
+        test.setNegativeFilters("b");
+        String actual = test.getGTestFilters();
+        assertEquals("--gtest_filter=-b", actual);
+    }
+
+    /**
+     * Test {@link GeeTestTest#getGTestFilters} with empty filters
+     * @throws DeviceNotAvailableException
+     */
+    public void testGetGTestFiltersWithNoFilters() {
+        GeeTest test = new GeeTest("package_foo", "exe_foo");
+        String actual = test.getGTestFilters();
+        assertEquals("", actual);
+    }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
index 6d87a61..bd48c51 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
@@ -25,6 +25,8 @@
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Unit tests for {@link TestPackageXmlParser}.
@@ -65,6 +67,29 @@
 
     private static final String NO_TEST_DATA = "<invalid />";
 
+    private static final String INSTANCED_TEST_DATA =
+        "<TestPackage>\n" +
+        "    <TestSuite name=\"com\" >\n" +
+        "        <TestSuite name=\"example\" >\n" +
+        "            <TestCase name=\"ExampleTest\" >\n" +
+        "                <Test name=\"testMultiInstanced\" >\n" +
+        "                    <TestInstance foo=\"bar\" />\n" +
+        "                    <TestInstance foo=\"baz\" foo2=\"baz2\"/>\n" +
+        "                </Test>\n" +
+        "                <Test name=\"testSingleInstanced\" >\n" +
+        "                    <TestInstance foo=\"bar\" />\n" +
+        "                </Test>\n" +
+        "                <Test name=\"testEmptyInstances\" >\n" +
+        "                    <TestInstance />\n" +
+        "                    <TestInstance />\n" +
+        "                </Test>\n" +
+        "                <Test name=\"testNotInstanced\" >\n" +
+        "                </Test>\n" +
+        "            </TestCase>\n" +
+        "        </TestSuite>\n" +
+        "    </TestSuite>\n" +
+        "</TestPackage>";
+
     /**
      * Test parsing test case xml containing an instrumentation test definition.
      */
@@ -162,6 +187,90 @@
         assertTrue(parser.getTestPackageDefs().isEmpty());
     }
 
+    /**
+     * Test parsing a test case xml with multiple test instances
+     */
+    public void testParse_instancedMultiple() throws ParseException  {
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
+        parser.parse(getStringAsStream(INSTANCED_TEST_DATA));
+        for (TestPackageDef def : parser.getTestPackageDefs()) {
+            final TestIdentifier testId =
+                    new TestIdentifier("com.example.ExampleTest", "testMultiInstanced");
+            final List<Map<String, String>> targetInstances =
+                    def.getTestInstanceArguments().get(testId);
+            assertNotNull(targetInstances);
+            assertEquals(2, targetInstances.size());
+
+            final Iterator<Map<String, String>> iterator = targetInstances.iterator();
+            final Map<String, String> firstInstance = iterator.next();
+            final Map<String, String> secondInstance = iterator.next();
+
+            assertEquals("bar", firstInstance.get("foo"));
+            assertEquals("baz", secondInstance.get("foo"));
+            assertEquals("baz2", secondInstance.get("foo2"));
+        }
+    }
+
+    /**
+     * Test parsing a test case xml with single test instance
+     */
+    public void testParse_instancedSingle() throws ParseException  {
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
+        parser.parse(getStringAsStream(INSTANCED_TEST_DATA));
+        for (TestPackageDef def : parser.getTestPackageDefs()) {
+            final TestIdentifier testId =
+                    new TestIdentifier("com.example.ExampleTest", "testSingleInstanced");
+            final List<Map<String, String>> targetInstances =
+                    def.getTestInstanceArguments().get(testId);
+            assertNotNull(targetInstances);
+            assertEquals(1, targetInstances.size());
+
+            final Iterator<Map<String, String>> iterator = targetInstances.iterator();
+            final Map<String, String> firstInstance = iterator.next();
+
+            assertEquals("bar", firstInstance.get("foo"));
+        }
+    }
+
+    /**
+     * Test parsing a test case xml with multiple test instances with no data
+     */
+    public void testParse_instancedEmptys() throws ParseException  {
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
+        parser.parse(getStringAsStream(INSTANCED_TEST_DATA));
+        for (TestPackageDef def : parser.getTestPackageDefs()) {
+            final TestIdentifier testId =
+                    new TestIdentifier("com.example.ExampleTest", "testEmptyInstances");
+            final List<Map<String, String>> targetInstances =
+                    def.getTestInstanceArguments().get(testId);
+            assertNotNull(targetInstances);
+            assertEquals(2, targetInstances.size());
+
+            final Iterator<Map<String, String>> iterator = targetInstances.iterator();
+            final Map<String, String> firstInstance = iterator.next();
+            final Map<String, String> secondInstance = iterator.next();
+
+            assertTrue(firstInstance.isEmpty());
+            assertTrue(secondInstance.isEmpty());
+        }
+    }
+
+    /**
+     * Test parsing a test case xml with no test instances
+     */
+    public void testParse_instancedNoInstances() throws ParseException  {
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
+        parser.parse(getStringAsStream(INSTANCED_TEST_DATA));
+        for (TestPackageDef def : parser.getTestPackageDefs()) {
+            final TestIdentifier testId =
+                    new TestIdentifier("com.example.ExampleTest", "testNotInstanced");
+            final List<Map<String, String>> targetInstances =
+                    def.getTestInstanceArguments().get(testId);
+            assertNotNull(targetInstances);
+            assertTrue(targetInstances.isEmpty());
+        }
+    }
+
     private InputStream getStringAsStream(String input) {
         return new ByteArrayInputStream(input.getBytes());
     }
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 4d04e1a..31229b1 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -335,6 +335,7 @@
       'com.android.cts.dram' : [],
       'com.android.cts.filesystemperf' : [],
       'com.android.cts.jank' : [],
+      'com.android.cts.jank2' : [],
       'com.android.cts.opengl' : [],
       'com.android.cts.simplecpu' : [],
       'com.android.cts.ui' : [],
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 88f2a53..e66ec7c 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -14,6 +14,28 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# test dex library
+# ============================================================
+include $(CLEAR_VARS)
+
+# custom variables used to generate test description. do not touch!
+LOCAL_SRC_FILES := $(call all-java-files-under, src/dot)
+
+LOCAL_MODULE := cts-tf-dalvik-lib
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+LOCAL_JAVA_LIBRARIES := junit-targetdex
+
+include $(BUILD_JAVA_LIBRARY)
+
+cts-tf-dalvik-lib.jack := $(full_classes_jack)
+
+private_jill_jarjar_asm := $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/,jill-jarjar-asm.jar)
+$(private_jill_jarjar_asm) : PRIVATE_JARJAR_RULES := $(LOCAL_PATH)/jill-jarjar-rules.txt
+$(private_jill_jarjar_asm) : $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/,jill.jar) | $(JARJAR)
+	@echo JarJar: $@
+	$(hide) java -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+
 # buildutil java library
 # ============================================================
 include $(CLEAR_VARS)
@@ -29,31 +51,46 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_JAVA_LIBRARIES := dx dasm cfassembler junit
-LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
+LOCAL_JAVA_LIBRARIES += jack
+
+LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR) $(private_jill_jarjar_asm)
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
 # Buid android.core.vm-tests-tf.jar
 # ============================================================
 #
+include $(CLEAR_VARS)
+
+LOCAL_JACK_ENABLED := $(strip $(LOCAL_JACK_ENABLED))
 intermediates := $(call intermediates-dir-for,JAVA_LIBRARIES,vm-tests-tf,HOST)
 vmteststf_jar := $(intermediates)/android.core.vm-tests-tf.jar
 vmteststf_dep_jars := $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/, cts-tf-dalvik-buildutil.jar dasm.jar dx.jar cfassembler.jar junit.jar)
+vmteststf_dep_jars += $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/, jack.jar)
+vmteststf_dep_jars += $(private_jill_jarjar_asm)
+
+$(vmteststf_jar): PRIVATE_JACK_VM_ARGS := $(LOCAL_JACK_VM_ARGS)
+$(vmteststf_jar): PRIVATE_JACK_EXTRA_ARGS := $(LOCAL_JACK_EXTRA_ARGS)
+
+ifdef LOCAL_JACK_ENABLED
+    vmteststf_dep_jars += $(cts-tf-dalvik-lib.jack)
+endif
+
 $(vmteststf_jar): PRIVATE_SRC_FOLDER := $(LOCAL_PATH)/src
-$(vmteststf_jar): PRIVATE_LIB_FOLDER := $(LOCAL_PATH)/lib
 $(vmteststf_jar): PRIVATE_INTERMEDIATES_CLASSES := $(call intermediates-dir-for,JAVA_LIBRARIES,cts-tf-dalvik-buildutil,HOST)/classes
 $(vmteststf_jar): PRIVATE_INTERMEDIATES := $(intermediates)/tests
 $(vmteststf_jar): PRIVATE_INTERMEDIATES_DEXCORE_JAR := $(intermediates)/tests/dot/junit/dexcore.jar
 $(vmteststf_jar): PRIVATE_INTERMEDIATES_MAIN_FILES := $(intermediates)/main_files
 $(vmteststf_jar): PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES := $(intermediates)/hostjunit_files
 $(vmteststf_jar): PRIVATE_CLASS_PATH := $(subst $(space),:,$(vmteststf_dep_jars)):$(HOST_JDK_TOOLS_JAR)
-$(vmteststf_jar) : $(vmteststf_dep_jars) $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
+ifndef LOCAL_JACK_ENABLED
+$(vmteststf_jar) : $(vmteststf_dep_jars) $(JACK_JAR) $(JILL_JAR) $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
 	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
 	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
 	# generated and compile the host side junit tests
 	@echo "Write generated Main_*.java files to $(PRIVATE_INTERMEDIATES_MAIN_FILES)"
 	$(hide) java -cp $(PRIVATE_CLASS_PATH) util.build.BuildDalvikSuite $(PRIVATE_SRC_FOLDER) $(PRIVATE_INTERMEDIATES) \
-		$(HOST_OUT_JAVA_LIBRARIES)/cts-tf-dalvik-buildutil.jar:$(PRIVATE_LIB_FOLDER)/junit.jar:$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar \
+		$(HOST_OUT_JAVA_LIBRARIES)/cts-tf-dalvik-buildutil.jar:$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar \
 		$(PRIVATE_INTERMEDIATES_MAIN_FILES) $(PRIVATE_INTERMEDIATES_CLASSES) $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES) $$RUN_VM_TESTS_RTO
 	@echo "Generate $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)"
 	$(hide) jar -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar \
@@ -62,6 +99,26 @@
 		$(if $(NO_OPTIMIZE_DX), --no-optimize) $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar && rm -f $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar
 	$(hide) cd $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/classes && zip -q -r ../../android.core.vm-tests-tf.jar .
 	$(hide) cd $(dir $@) && zip -q -r android.core.vm-tests-tf.jar tests
+else # LOCAL_JACK_ENABLED
+$(vmteststf_jar) : $(vmteststf_dep_jars) $(JACK_JAR) $(JILL_JAR) out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jack $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar 
+	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
+	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
+	# generated and compile the host side junit tests
+	@echo "Write generated Main_*.java files to $(PRIVATE_INTERMEDIATES_MAIN_FILES)"
+	$(hide) java -cp $(PRIVATE_CLASS_PATH) util.build.JackBuildDalvikSuite $(PRIVATE_SRC_FOLDER) $(PRIVATE_INTERMEDIATES) \
+		out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jack:$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar \
+		$(PRIVATE_INTERMEDIATES_MAIN_FILES) $(PRIVATE_INTERMEDIATES_CLASSES) $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES) $$RUN_VM_TESTS_RTO
+	@echo "Generate $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)"
+	$(hide) jar -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)-class.jar \
+		$(addprefix -C $(PRIVATE_INTERMEDIATES_CLASSES) , dot/junit/DxUtil.class dot/junit/DxAbstractMain.class)
+	$(hide) $(JILL) --output $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jack $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)-class.jar
+	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).tmp
+	$(hide) $(call call-jack,$(PRIVATE_JACK_VM_ARGS),$(PRIVATE_JACK_EXTRA_ARGS)) --output-dex $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).tmp \
+		$(if $(NO_OPTIMIZE_DX), -D jack.dex.optimize "false") --import $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jack && rm -f $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jack
+	$(hide) cd $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).tmp && zip -q -r $(abspath $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)) .
+	$(hide) cd $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/classes && zip -q -r ../../android.core.vm-tests-tf.jar .
+	$(hide) cd $(dir $@) && zip -q -r android.core.vm-tests-tf.jar tests
+endif # LOCAL_JACK_ENABLED
 
 # Clean up temp vars
 intermediates :=
diff --git a/tools/vm-tests-tf/jill-jarjar-rules.txt b/tools/vm-tests-tf/jill-jarjar-rules.txt
new file mode 100644
index 0000000..ee6f403
--- /dev/null
+++ b/tools/vm-tests-tf/jill-jarjar-rules.txt
@@ -0,0 +1 @@
+rule org.objectweb.** com.android.jill.@0
\ No newline at end of file
diff --git a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
index 63794df..0e31884 100644
--- a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
+++ b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
@@ -78,6 +78,7 @@
 
     private int testClassCnt = 0;
     private int testMethodsCnt = 0;
+    private boolean useJack;
 
     /*
      * using a linked hashmap to keep the insertion order for iterators.
@@ -101,39 +102,47 @@
      */
     public static void main(String[] args) throws IOException {
 
-        if (args.length > 5) {
-            JAVASRC_FOLDER = args[0];
-            OUTPUT_FOLDER = args[1];
-            CLASS_PATH = args[2];
-            MAIN_SRC_OUTPUT_FOLDER = args[3];
-            CLASSES_OUTPUT_FOLDER = MAIN_SRC_OUTPUT_FOLDER + "/classes";
-
-            COMPILED_CLASSES_FOLDER = args[4];
-
-            HOSTJUNIT_SRC_OUTPUT_FOLDER = args[5];
-            HOSTJUNIT_CLASSES_OUTPUT_FOLDER = HOSTJUNIT_SRC_OUTPUT_FOLDER + "/classes";
-
-            if (args.length > 6) {
-                // optional: restrict to e.g. "opcodes.add_double"
-                restrictTo = args[6];
-                System.out.println("restricting build to: " + restrictTo);
-            }
-
-        } else {
-            System.out.println("usage: java-src-folder output-folder classpath " +
-                    "generated-main-files compiled_output generated-main-files " +
-            "[restrict-to-opcode]");
-            System.exit(-1);
-        }
+        parseArgs(args);
 
         long start = System.currentTimeMillis();
-        BuildDalvikSuite cat = new BuildDalvikSuite();
+        BuildDalvikSuite cat = new BuildDalvikSuite(false);
         cat.compose();
         long end = System.currentTimeMillis();
 
         System.out.println("elapsed seconds: " + (end - start) / 1000);
     }
 
+    public static void parseArgs(String[] args) {
+      if (args.length > 5) {
+          JAVASRC_FOLDER = args[0];
+          OUTPUT_FOLDER = args[1];
+          CLASS_PATH = args[2];
+          MAIN_SRC_OUTPUT_FOLDER = args[3];
+          CLASSES_OUTPUT_FOLDER = MAIN_SRC_OUTPUT_FOLDER + "/classes";
+
+          COMPILED_CLASSES_FOLDER = args[4];
+
+          HOSTJUNIT_SRC_OUTPUT_FOLDER = args[5];
+          HOSTJUNIT_CLASSES_OUTPUT_FOLDER = HOSTJUNIT_SRC_OUTPUT_FOLDER + "/classes";
+
+          if (args.length > 6) {
+              // optional: restrict to e.g. "opcodes.add_double"
+              restrictTo = args[6];
+              System.out.println("restricting build to: " + restrictTo);
+          }
+
+      } else {
+          System.out.println("usage: java-src-folder output-folder classpath " +
+                  "generated-main-files compiled_output generated-main-files " +
+          "[restrict-to-opcode]");
+          System.exit(-1);
+      }
+    }
+
+    public BuildDalvikSuite(boolean useJack) {
+      this.useJack = useJack;
+    }
+
     public void compose() throws IOException {
         System.out.println("Collecting all junit tests...");
         new TestRunner() {
@@ -182,19 +191,21 @@
         li.add(method);
     }
     private String curJunitFileName = null;
+    private String curJunitName = null;
     private String curJunitFileData = "";
 
-    private JavacBuildStep javacHostJunitBuildStep;
+    private SourceBuildStep hostJunitBuildStep;
 
     private void flushHostJunitFile() {
         if (curJunitFileName != null) {
             File toWrite = new File(curJunitFileName);
             String absPath = toWrite.getAbsolutePath();
             // add to java source files for later compilation
-            javacHostJunitBuildStep.addSourceFile(absPath);
+            hostJunitBuildStep.addSourceFile(absPath);
             // write file
             curJunitFileData += "\n}\n";
             writeToFileMkdir(toWrite, curJunitFileData);
+
             curJunitFileName = null;
             curJunitFileData = "";
         }
@@ -274,11 +285,11 @@
         String datafileContent = "";
         Set<BuildStep> targets = new TreeSet<BuildStep>();
 
-        javacHostJunitBuildStep = new JavacBuildStep(HOSTJUNIT_CLASSES_OUTPUT_FOLDER, CLASS_PATH);
+        SourceBuildStep srcBuildStep;
+        hostJunitBuildStep = new JavacBuildStep(
+            HOSTJUNIT_CLASSES_OUTPUT_FOLDER, CLASS_PATH);
 
-
-        JavacBuildStep javacBuildStep = new JavacBuildStep(
-                CLASSES_OUTPUT_FOLDER, CLASS_PATH);
+        srcBuildStep = new JavacBuildStep(CLASSES_OUTPUT_FOLDER, CLASS_PATH);
 
         for (Entry<String, List<String>> entry : map.entrySet()) {
 
@@ -341,19 +352,25 @@
                 "    public static void main(String[] args) throws Exception {" +
                 methodContent + "\n}\n";
 
-                String fileName = getFileName(pName, method, ".java");
                 File sourceFile = getFileFromPackage(pName, method);
 
-                File classFile = new File(CLASSES_OUTPUT_FOLDER + "/" +
-                        getFileName(pName, method, ".class"));
-                // if (sourceFile.lastModified() > classFile.lastModified()) {
                 writeToFile(sourceFile, content);
-                javacBuildStep.addSourceFile(sourceFile.getAbsolutePath());
+                if (useJack) {
+                    File jackFile = new File(CLASSES_OUTPUT_FOLDER + "/" +
+                            getFileName(pName, method, ".jack"));
+                    JackBuildStep step = new JackBuildStep(jackFile.getAbsolutePath(), CLASS_PATH);
+                    step.addSourceFile(sourceFile.getAbsolutePath());
+                    if (!step.build()) {
+                        System.out.println("main src dalvik-cts-buildutil build step failed");
+                        System.exit(1);
+                    }
+                } else {
+                    srcBuildStep.addSourceFile(sourceFile.getAbsolutePath());
+                }
 
                 BuildStep dexBuildStep = generateDexBuildStep(
-                        CLASSES_OUTPUT_FOLDER, getFileName(pName, method, ""));
+                        CLASSES_OUTPUT_FOLDER, getFileName(pName, method, ""), null);
                 targets.add(dexBuildStep);
-                // }
 
 
                 // prepare the entry in the data file for the bash script.
@@ -449,22 +466,23 @@
         scriptDataDir.mkdirs();
         writeToFile(new File(scriptDataDir, "scriptdata"), datafileContent);
 
-        if (!javacHostJunitBuildStep.build()) {
+        if (!hostJunitBuildStep.build()) {
             System.out.println("main javac cts-host-hostjunit-classes build step failed");
             System.exit(1);
         }
 
-        if (javacBuildStep.build()) {
-            for (BuildStep buildStep : targets) {
-                if (!buildStep.build()) {
-                    System.out.println("building failed. buildStep: " +
-                            buildStep.getClass().getName() + ", " + buildStep);
-                    System.exit(1);
-                }
+        if (!useJack) {
+            if (!srcBuildStep.build()) {
+                System.out.println("main src dalvik-cts-buildutil build step failed");
+                System.exit(1);
             }
-        } else {
-            System.out.println("main javac dalvik-cts-buildutil build step failed");
-            System.exit(1);
+        }
+        for (BuildStep buildStep : targets) {
+            if (!buildStep.build()) {
+                System.out.println("building failed. buildStep: " +
+                        buildStep.getClass().getName() + ", " + buildStep);
+                System.exit(1);
+            }
         }
     }
 
@@ -521,19 +539,37 @@
             return;
         }
 
-        if (new File(sourceFolder, fileName + ".java").exists()) {
-
+        File srcFile = new File(sourceFolder, fileName + ".java");
+        if (srcFile.exists()) {
+            JackBuildStep jackBuildStep = null;
+            if (useJack) {
+                jackBuildStep = new JackBuildStep(
+                        COMPILED_CLASSES_FOLDER + File.separator + fileName + ".jack",
+                        CLASS_PATH);
+                jackBuildStep.addSourceFile(srcFile.getAbsolutePath());
+            }
             BuildStep dexBuildStep = generateDexBuildStep(
-                    COMPILED_CLASSES_FOLDER, fileName);
+                COMPILED_CLASSES_FOLDER, fileName, jackBuildStep);
             targets.add(dexBuildStep);
             return;
         }
 
         try {
             if (Class.forName(dependentTestClassName) != null) {
+                JillBuildStep jillBuildStep = null;
+                if (useJack) {
+                    BuildStep.BuildFile classFile = new BuildStep.BuildFile(
+                        COMPILED_CLASSES_FOLDER, fileName + ".class");
 
+                    BuildStep.BuildFile jackFile = new BuildStep.BuildFile(
+                        COMPILED_CLASSES_FOLDER,
+                        fileName + ".jack");
+
+                    jillBuildStep = new JillBuildStep(classFile,
+                        jackFile);
+                }
                 BuildStep dexBuildStep = generateDexBuildStep(
-                        COMPILED_CLASSES_FOLDER, fileName);
+                    COMPILED_CLASSES_FOLDER, fileName, jillBuildStep);
                 targets.add(dexBuildStep);
                 return;
             }
@@ -546,24 +582,50 @@
     }
 
     private BuildStep generateDexBuildStep(String classFileFolder,
-            String classFileName) {
-        BuildStep.BuildFile classFile = new BuildStep.BuildFile(
-                classFileFolder, classFileName + ".class");
+            String classFileName, BuildStep dependency) {
+        if (!useJack) {
+            BuildStep.BuildFile classFile = new BuildStep.BuildFile(
+                    classFileFolder, classFileName + ".class");
 
-        BuildStep.BuildFile tmpJarFile = new BuildStep.BuildFile(OUTPUT_FOLDER,
-                classFileName + "_tmp.jar");
+            BuildStep.BuildFile tmpJarFile = new BuildStep.BuildFile(
+                    OUTPUT_FOLDER,
+                    classFileName + "_tmp.jar");
 
-        JarBuildStep jarBuildStep = new JarBuildStep(classFile, classFileName +
-                ".class", tmpJarFile, false);
+            JarBuildStep jarBuildStep = new JarBuildStep(classFile,
+                    classFileName + ".class", tmpJarFile, false);
 
-        BuildStep.BuildFile outputFile = new BuildStep.BuildFile(OUTPUT_FOLDER,
-                classFileName + ".jar");
+            if (dependency != null) {
+                jarBuildStep.addChild(dependency);
+            }
 
-        DexBuildStep dexBuildStep = new DexBuildStep(tmpJarFile, outputFile,
-                true);
+            BuildStep.BuildFile outputFile = new BuildStep.BuildFile(
+                    OUTPUT_FOLDER,
+                    classFileName + ".jar");
 
-        dexBuildStep.addChild(jarBuildStep);
-        return dexBuildStep;
+            DxBuildStep dexBuildStep = new DxBuildStep(tmpJarFile,
+                    outputFile,
+                    true);
+
+            dexBuildStep.addChild(jarBuildStep);
+            return dexBuildStep;
+        } else {
+          BuildStep.BuildFile jackFile = new BuildStep.BuildFile(
+              classFileFolder, classFileName + ".jack");
+
+          BuildStep.BuildFile outputFile = new BuildStep.BuildFile(
+                  OUTPUT_FOLDER,
+                  classFileName + ".jar");
+
+          JackDexBuildStep dexBuildStep = new JackDexBuildStep(jackFile,
+                  outputFile,
+                  true);
+
+          if (dependency != null) {
+              dexBuildStep.addChild(dependency);
+          }
+          return dexBuildStep;
+
+        }
 
     }
 
@@ -754,7 +816,7 @@
 
     private void writeToFile(File file, String content) {
         try {
-            if (file.length() == content.length()) {
+            if (file.exists() && file.length() == content.length()) {
                 FileReader reader = new FileReader(file);
                 char[] charContents = new char[(int) file.length()];
                 reader.read(charContents);
diff --git a/tools/vm-tests-tf/src/util/build/DexBuildStep.java b/tools/vm-tests-tf/src/util/build/DxBuildStep.java
similarity index 93%
rename from tools/vm-tests-tf/src/util/build/DexBuildStep.java
rename to tools/vm-tests-tf/src/util/build/DxBuildStep.java
index 6aba51c..6e347b2 100644
--- a/tools/vm-tests-tf/src/util/build/DexBuildStep.java
+++ b/tools/vm-tests-tf/src/util/build/DxBuildStep.java
@@ -19,11 +19,11 @@
 import com.android.dx.command.dexer.Main;
 import java.io.IOException;
 
-public class DexBuildStep extends BuildStep {
+public class DxBuildStep extends BuildStep {
 
     private final boolean deleteInputFileAfterBuild;
 
-    DexBuildStep(BuildFile inputFile, BuildFile outputFile,
+    DxBuildStep(BuildFile inputFile, BuildFile outputFile,
             boolean deleteInputFileAfterBuild) {
         super(inputFile, outputFile);
         this.deleteInputFileAfterBuild = deleteInputFileAfterBuild;
@@ -71,7 +71,7 @@
     @Override
     public boolean equals(Object obj) {
         if (super.equals(obj)) {
-            DexBuildStep other = (DexBuildStep) obj;
+            DxBuildStep other = (DxBuildStep) obj;
 
             return inputFile.equals(other.inputFile)
                     && outputFile.equals(other.outputFile);
diff --git a/tools/vm-tests-tf/src/util/build/JackBuildDalvikSuite.java b/tools/vm-tests-tf/src/util/build/JackBuildDalvikSuite.java
new file mode 100644
index 0000000..a508e5b
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JackBuildDalvikSuite.java
@@ -0,0 +1,34 @@
+/*
+ * 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 util.build;
+
+import java.io.IOException;
+
+public class JackBuildDalvikSuite {
+
+    public static void main(String[] args) throws IOException {
+
+        BuildDalvikSuite.parseArgs(args);
+
+        long start = System.currentTimeMillis();
+        BuildDalvikSuite cat = new BuildDalvikSuite(true);
+        cat.compose();
+        long end = System.currentTimeMillis();
+
+        System.out.println("elapsed seconds: " + (end - start) / 1000);
+    }
+}
diff --git a/tools/vm-tests-tf/src/util/build/JackBuildStep.java b/tools/vm-tests-tf/src/util/build/JackBuildStep.java
new file mode 100644
index 0000000..1e1ede6
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JackBuildStep.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package util.build;
+
+import com.android.jack.Jack;
+import com.android.jack.Main;
+import com.android.jack.Options;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class JackBuildStep extends SourceBuildStep {
+
+    private final String destPath;
+    private final String classPath;
+    private final Set<String> sourceFiles = new HashSet<String>();
+
+    public JackBuildStep(String destPath, String classPath) {
+        this.destPath = destPath;
+        this.classPath = classPath;
+    }
+
+    @Override
+    public void addSourceFile(String sourceFile) {
+        sourceFiles.add(sourceFile);
+    }
+
+    @Override
+    boolean build() {
+        if (super.build()) {
+            if (sourceFiles.isEmpty()) {
+                return true;
+            }
+
+            File outDir = new File(destPath).getParentFile();
+            if (!outDir.exists() && !outDir.mkdirs()) {
+                System.err.println("failed to create output dir: "
+                        + outDir.getAbsolutePath());
+                return false;
+            }
+            List<String> commandLine = new ArrayList(4 + sourceFiles.size());
+            commandLine.add("--verbose");
+            commandLine.add("error");
+            commandLine.add("--classpath");
+            commandLine.add(classPath);
+            commandLine.add("--output-jack");
+            commandLine.add(destPath);
+            commandLine.addAll(sourceFiles);
+
+            try {
+                Options options = Main.parseCommandLine(commandLine);
+                Jack.checkAndRun(options);
+            } catch (Throwable ex) {
+                ex.printStackTrace();
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (super.equals(obj)) {
+            JackBuildStep other = (JackBuildStep) obj;
+            return destPath.equals(other.destPath) && classPath.equals(other.classPath)
+                    && sourceFiles.equals(other.sourceFiles);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return destPath.hashCode() ^ classPath.hashCode() ^ sourceFiles.hashCode();
+    }
+}
diff --git a/tools/vm-tests-tf/src/util/build/JackDexBuildStep.java b/tools/vm-tests-tf/src/util/build/JackDexBuildStep.java
new file mode 100644
index 0000000..304eaa0
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JackDexBuildStep.java
@@ -0,0 +1,96 @@
+/*
+ * 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 util.build;
+
+import com.android.jack.Jack;
+import com.android.jack.Main;
+import com.android.jack.Options;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JackDexBuildStep extends BuildStep {
+
+    private final boolean deleteInputFileAfterBuild;
+
+    JackDexBuildStep(BuildFile inputFile, BuildFile outputFile,
+            boolean deleteInputFileAfterBuild) {
+        super(inputFile, outputFile);
+        this.deleteInputFileAfterBuild = deleteInputFileAfterBuild;
+    }
+
+    @Override
+    boolean build() {
+
+        if (super.build()) {
+            String outputFilePath = outputFile.fileName.getAbsolutePath();
+            if (outputFilePath.endsWith(".dex")) {
+              throw new AssertionError(
+                  "DexBuildStep does not support dex output outside of an archive");
+            }
+
+            File outDir = outputFile.fileName.getParentFile();
+            if (!outDir.exists() && !outDir.mkdirs()) {
+                System.err.println("failed to create output dir: "
+                        + outDir.getAbsolutePath());
+                return false;
+            }
+
+            List<String> commandLine = new ArrayList<String>(4);
+            commandLine.add("--verbose");
+            commandLine.add("error");
+            commandLine.add("--output-dex-zip");
+            commandLine.add(outputFilePath);
+            commandLine.add("--import");
+            commandLine.add(inputFile.fileName.getAbsolutePath());
+
+            try {
+               Options options = Main.parseCommandLine(commandLine);
+               Jack.checkAndRun(options);
+                if (deleteInputFileAfterBuild) {
+                    inputFile.fileName.delete();
+                }
+                return true;
+            } catch (Throwable ex) {
+                System.err.println("exception while dexing "
+                        + inputFile.fileName.getAbsolutePath() + " to "
+                        + outputFile.fileName.getAbsolutePath());
+                ex.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return inputFile.hashCode() ^ outputFile.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (super.equals(obj)) {
+            JackDexBuildStep other = (JackDexBuildStep) obj;
+
+            return inputFile.equals(other.inputFile)
+                    && outputFile.equals(other.outputFile);
+        }
+        return false;
+    }
+
+
+}
diff --git a/tools/vm-tests-tf/src/util/build/JavacBuildStep.java b/tools/vm-tests-tf/src/util/build/JavacBuildStep.java
index 7d7033f..d08a2c6 100644
--- a/tools/vm-tests-tf/src/util/build/JavacBuildStep.java
+++ b/tools/vm-tests-tf/src/util/build/JavacBuildStep.java
@@ -23,7 +23,7 @@
 import java.util.HashSet;
 import java.util.Set;
 
-public class JavacBuildStep extends BuildStep {
+public class JavacBuildStep extends SourceBuildStep {
 
     private final String destPath;
     private final String classPath;
@@ -32,12 +32,13 @@
         this.destPath = destPath;
         this.classPath = classPath;
     }
-    
+
+    @Override
     public void addSourceFile(String sourceFile)
     {
         sourceFiles.add(sourceFile);
     }
-    
+
     @Override
     boolean build() {
         if (super.build())
@@ -46,7 +47,7 @@
             {
                 return true;
             }
-            
+
             File destFile = new File(destPath);
             if (!destFile.exists() && !destFile.mkdirs())
             {
@@ -59,13 +60,12 @@
             commandLine[1] = classPath;
             commandLine[2] = "-d";
             commandLine[3] = destPath;
-             
+
             String[] files = new String[sourceFiles.size()];
             sourceFiles.toArray(files);
-            
+
             System.arraycopy(files, 0, commandLine, args, files.length);
-            
-            
+
             return Main.compile(commandLine, new PrintWriter(System.err)) == 0;
         }
         return false;
@@ -73,17 +73,16 @@
 
     @Override
     public boolean equals(Object obj) {
-        // TODO Auto-generated method stub
         if (super.equals(obj))
         {
             JavacBuildStep other = (JavacBuildStep) obj;
-            return destPath.equals(other.destPath) 
+            return destPath.equals(other.destPath)
                 && classPath.equals(other.classPath)
                 && sourceFiles.equals(other.sourceFiles);
         }
         return false;
     }
-    
+
     @Override
     public int hashCode() {
         return destPath.hashCode() ^ classPath.hashCode() ^ sourceFiles.hashCode();
diff --git a/tools/vm-tests-tf/src/util/build/JillBuildStep.java b/tools/vm-tests-tf/src/util/build/JillBuildStep.java
new file mode 100644
index 0000000..d2e435e
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JillBuildStep.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package util.build;
+
+import com.android.jill.Jill;
+import com.android.jill.Main;
+import com.android.jill.Options;
+
+import java.io.File;
+
+public class JillBuildStep extends BuildStep {
+
+    JillBuildStep(BuildFile inputFile, BuildFile outputFile) {
+        super(inputFile, outputFile);
+    }
+
+    @Override
+    boolean build() {
+        if (super.build()) {
+
+            File outDir = outputFile.fileName.getParentFile();
+            if (!outDir.exists() && !outDir.mkdirs()) {
+                System.err.println("failed to create output dir: "
+                        + outDir.getAbsolutePath());
+                return false;
+            }
+
+            int args = 3;
+            String[] commandLine = new String[args];
+            commandLine[0] = "--output";
+            commandLine[1] = outputFile.fileName.getAbsolutePath();
+            commandLine[2] = inputFile.fileName.getAbsolutePath();
+
+            try {
+                Options options = Main.getOptions(commandLine);
+                Jill.process(options);
+            } catch (Throwable ex) {
+                ex.printStackTrace();
+                return false;
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (super.equals(obj)) {
+            JillBuildStep other = (JillBuildStep) obj;
+
+            return inputFile.equals(other.inputFile) && outputFile.equals(other.outputFile);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return inputFile.hashCode() ^ outputFile.hashCode();
+    }
+}
diff --git a/tests/print/src/android/print/cts/IPrivilegedOperations.aidl b/tools/vm-tests-tf/src/util/build/SourceBuildStep.java
similarity index 74%
rename from tests/print/src/android/print/cts/IPrivilegedOperations.aidl
rename to tools/vm-tests-tf/src/util/build/SourceBuildStep.java
index 93c8c3e..4a68a05 100644
--- a/tests/print/src/android/print/cts/IPrivilegedOperations.aidl
+++ b/tools/vm-tests-tf/src/util/build/SourceBuildStep.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package android.print.cts;
+package util.build;
 
-interface IPrivilegedOperations {
-    boolean clearApplicationUserData(String packageName);
+public abstract class SourceBuildStep extends BuildStep {
+
+  public abstract void addSourceFile(String sourceFile);
+
 }