Merge "Test ContactsContract_StreamItems Insert"
diff --git a/Android.mk b/Android.mk
index 159bda0..4251262 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,6 +14,6 @@
 # limitations under the License.
 #
 
-include cts/CtsNativeTestCase.mk
-include cts/CtsTestCoverage.mk
+include cts/CtsBuild.mk
+include cts/CtsCoverage.mk
 include $(call all-subdir-makefiles)
diff --git a/CtsBuild.mk b/CtsBuild.mk
new file mode 100644
index 0000000..b4273bd
--- /dev/null
+++ b/CtsBuild.mk
@@ -0,0 +1,66 @@
+# 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)
+
+# CTS build rules that are needed to generate the corresponding XML
+# for a test package. CTS needs these XML files to know what tests
+# to run as well as detect which ones were not executed.
+#
+# 1. Replace the regular build command with the CTS variant:
+#
+#    BUILD_EXECUTABLE -> BUILD_CTS_EXECUTABLE
+#    BUILD_PACKAGE -> BUILD_CTS_PACKAGE
+#    BUILD_HOST_JAVA_LIBRARY -> BUILD_HOST_JAVA_LIBRARY
+#
+# 2. Define LOCAL_CTS_TEST_PACKAGE if you are using
+#    BUILD_EXECUTABLE or BUILD_HOST_JAVA_LIBRARY.
+#
+BUILD_CTS_EXECUTABLE := $(LOCAL_PATH)/tools/build/test_executable.mk
+BUILD_CTS_PACKAGE := $(LOCAL_PATH)/tools/build/test_package.mk
+BUILD_CTS_HOST_JAVA_LIBRARY := $(LOCAL_PATH)/tools/build/test_host_java_library.mk
+
+# 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
+
+# Scanners of source files for tests which are then inputed into
+# the XML generator to produce test XMLs.
+CTS_NATIVE_TEST_SCANNER := $(HOST_OUT_EXECUTABLES)/cts-native-scanner
+CTS_JAVA_TEST_SCANNER := $(HOST_OUT_EXECUTABLES)/cts-java-scanner
+CTS_JAVA_TEST_SCANNER_DOCLET := $(HOST_OUT_JAVA_LIBRARIES)/cts-java-scanner-doclet.jar
+
+# Generator of test XMLs from scanner output.
+CTS_XML_GENERATOR := $(HOST_OUT_EXECUTABLES)/cts-xml-generator
+
+# File indicating which tests should be blacklisted due to problems.
+CTS_EXPECTATIONS := cts/tests/expectations/knownfailures.txt
+
+# Functions to get the paths of the build outputs.
+
+define cts-get-lib-paths
+	$(foreach lib,$(1),$(HOST_OUT_JAVA_LIBRARIES)/$(lib).jar)
+endef
+
+define cts-get-native-paths
+	$(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe))/$(exe))
+endef
+
+define cts-get-package-paths
+	$(foreach pkg,$(1),$(CTS_TESTCASES_OUT)/$(pkg).apk)
+endef
+
+define cts-get-test-xmls
+	$(foreach name,$(1),$(CTS_TESTCASES_OUT)/$(name).xml)
+endef
diff --git a/CtsTestCoverage.mk b/CtsCoverage.mk
similarity index 100%
rename from CtsTestCoverage.mk
rename to CtsCoverage.mk
diff --git a/CtsNativeTestCase.mk b/CtsNativeTestCase.mk
deleted file mode 100644
index cd027e6..0000000
--- a/CtsNativeTestCase.mk
+++ /dev/null
@@ -1,36 +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 this file to gain access to functions to build native CTS
-# test packages. Replace "include $(BUILD_EXECUTABLE)" with
-# "include $(BUILD_CTS_EXECUTABLE)".
-
-LOCAL_PATH := $(call my-dir)
-BUILD_CTS_EXECUTABLE := $(LOCAL_PATH)/tools/build/test_executable.mk
-
-CTS_NATIVE_XML_OUT := $(HOST_OUT)/cts-native-xml
-
-CTS_NATIVE_TEST_SCANNER := $(HOST_OUT_EXECUTABLES)/cts-native-scanner
-
-CTS_XML_GENERATOR := $(HOST_OUT_EXECUTABLES)/cts-xml-generator
-
-CTS_EXPECTATIONS := cts/tests/expectations/knownfailures.txt
-
-define cts-get-native-paths
-	$(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe))/$(exe))
-endef
-
-define cts-get-native-xmls
-	$(foreach exe,$(1),$(CTS_NATIVE_XML_OUT)/$(exe).xml)
-endef
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 840d42b..70f3ef9 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -24,10 +24,22 @@
 	CtsTargetInstrumentationApp \
 	CtsUsePermissionDiffCert
 
-# These test cases will be analyzed by the CTS API coverage tools. 
-CTS_COVERAGE_TEST_CASE_LIST := \
-	CtsAccelerationTestCases \
+# Any APKs that need to be copied to the CTS distribution's testcases
+# directory but do not require an associated test package XML.
+CTS_TEST_CASE_LIST := \
+	TestDeviceSetup \
 	CtsAccelerationTestStubs \
+	CtsDelegatingAccessibilityService \
+	CtsDeviceAdmin \
+	CtsTestStubs \
+	SignatureTest \
+	ApiDemos \
+	ApiDemosReferenceTest \
+	$(CTS_SECURITY_APPS_LIST)
+
+# Test packages that require an associated test package XML.
+CTS_TEST_PACKAGES := \
+	CtsAccelerationTestCases \
 	CtsAccessibilityServiceTestCases \
 	CtsAccountManagerTestCases \
 	CtsAdminTestCases \
@@ -61,30 +73,37 @@
 	CtsSecurityTestCases \
 	CtsSpeechTestCases \
 	CtsTelephonyTestCases \
-	CtsTestStubs \
 	CtsTextTestCases \
 	CtsUtilTestCases \
 	CtsViewTestCases \
 	CtsWebkitTestCases \
 	CtsWidgetTestCases
 
-CTS_TEST_CASE_LIST := \
-	TestDeviceSetup \
-	CtsDelegatingAccessibilityService \
-	CtsDeviceAdmin \
-	SignatureTest \
-	ApiDemos \
-	ApiDemosReferenceTest \
-	$(CTS_COVERAGE_TEST_CASE_LIST) \
-	$(CTS_SECURITY_APPS_LIST)
+# All APKs that need to be scanned by the coverage utilities.
+CTS_COVERAGE_TEST_CASE_LIST := \
+	$(CTS_TEST_CASE_LIST) \
+	$(CTS_TEST_PACKAGES)
 
+# Host side only tests
+CTS_HOST_LIBRARIES := \
+    CtsAppSecurityTests
+
+# Native test executables that need to have associated test XMLs.
 CTS_NATIVE_EXES := \
 	NativeMediaTest_SL \
 	NativeMediaTest_XA
 
-CTS_TEST_CASES := $(call cts-get-native-paths,$(CTS_NATIVE_EXES))
+# All the files that will end up under the repository/testcases
+# directory of the final CTS distribution.
+CTS_TEST_CASES := $(call cts-get-lib-paths,$(CTS_HOST_LIBRARIES)) \
+		$(call cts-get-package-paths,$(CTS_TEST_PACKAGES)) \
+		$(call cts-get-native-paths,$(CTS_NATIVE_EXES))
 
-CTS_TEST_XMLS := $(call cts-get-native-xmls,$(CTS_NATIVE_EXES))
+# All the XMLs that will end up under the repository/testcases
+# and that need to be created before making the final CTS distribution.
+CTS_TEST_XMLS := $(call cts-get-test-xmls,$(CTS_HOST_LIBRARIES)) \
+		$(call cts-get-test-xmls,$(CTS_TEST_PACKAGES)) \
+		$(call cts-get-test-xmls,$(CTS_NATIVE_EXES))
 
 # The following files will be placed in the tools directory of the CTS distribution
 CTS_TOOLS_LIST :=
diff --git a/apps/CtsVerifier/jni/audioquality/Android.mk b/apps/CtsVerifier/jni/audioquality/Android.mk
index 8e827f7..787128a 100644
--- a/apps/CtsVerifier/jni/audioquality/Android.mk
+++ b/apps/CtsVerifier/jni/audioquality/Android.mk
@@ -20,11 +20,13 @@
 
 LOCAL_MODULE_TAGS := optional
 
-
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
 
 LOCAL_MODULE    := libaudioquality
 LOCAL_SRC_FILES := Fft.cpp Window.cpp GlitchTest.cpp MeasureRms.cpp \
    OverflowCheck.cpp LinearityTest.cpp CompareSpectra.cpp \
-   GenerateSinusoid.cpp Wrapper.cpp
+   GenerateSinusoid.cpp Wrapper.cpp LinearityTestRms.cpp
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/apps/CtsVerifier/jni/audioquality/LinearityTest.h b/apps/CtsVerifier/jni/audioquality/LinearityTest.h
index d92566a..1aac4b6 100644
--- a/apps/CtsVerifier/jni/audioquality/LinearityTest.h
+++ b/apps/CtsVerifier/jni/audioquality/LinearityTest.h
@@ -17,6 +17,22 @@
 #ifndef LINEARITY_TEST_H
 #define LINEARITY_TEST_H
 
+/* error codes returned */
+// The input signals or sample counts are missing.
+const int ERROR_INPUT_SIGNAL_MISSING       = -1;
+// The number of input signals is < 2.
+const int ERROR_INPUT_SIGNAL_NUMBERS       = -2;
+// The specified sample rate is <= 4000.0
+const int ERROR_SAMPLE_RATE_TOO_LOW        = -3;
+// The dB step size for the increase in stimulus level is <= 0.0
+const int ERROR_NEGATIVE_STEP_SIZE         = -4;
+// The specified reference stimulus number is out of range.
+const int ERROR_STIMULUS_NUMBER            = -5;
+// One or more of the stimuli is too short in duration.
+const int ERROR_STIMULI_TOO_SHORT          = -6;
+// cannot find linear fitting for the given data
+const int ERROR_LINEAR_FITTING             = -7;
+
 /* There are numSignals int16 signals in pcms.  sampleCounts is an
    integer array of length numSignals containing their respective
    lengths in samples.  They are all sampled at sampleRate.  The pcms
@@ -27,16 +43,15 @@
    normal speaking levels).  The maximum deviation in linearity found
    (in dB) is returned in maxDeviation.  The function returns 1 if
    the measurements could be made, or a negative number that
-   indicates the error, as follows:
-      -1 The input signals or sample counts are missing.
-      -2 The number of input signals is < 2.
-      -3 The specified sample rate is <= 4000.0
-      -4 The dB step size for the increase in stimulus level is <= 0.0/
-      -5 The specified reverence stimulus number is out of range.
-      -6 One or more of the stimuli is too short in duration. */
+   indicates the error, as defined above. */
 int linearityTest(short** pcms, int* sampleCounts, int numSignals,
                   float sampleRate, float dbStepSize,
                   int referenceStim, float* maxDeviation);
 
+/* a version using RMS of the whole signal and linear fitting */
+int linearityTestRms(short** pcms, int* sampleCounts, int numSignals,
+                  float sampleRate, float dbStepSize,
+                  float* maxDeviation);
+
 
 #endif /* LINEARITY_TEST_H */
diff --git a/apps/CtsVerifier/jni/audioquality/LinearityTestRms.cpp b/apps/CtsVerifier/jni/audioquality/LinearityTestRms.cpp
new file mode 100644
index 0000000..d83b056
--- /dev/null
+++ b/apps/CtsVerifier/jni/audioquality/LinearityTestRms.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+/* This test accepts a collection of N speech waveforms collected as
+   part of N recognition attempts.  The waveforms are ordered by
+   increasing presentation level.  The test determines the extent to
+   which the peak amplitudes in the waveforms track the change in
+   presentation level.  Failure to track the presentation level within
+   some reasonable margin is an indication of clipping or of automatic
+   gain control in the signal path.
+
+   RMS of each level is used as a parameter for deciding lienairy.
+   For each level, RMS is calculated, and a line fitting into RMS vs level
+   will be calculated. Then for each level, residual error of measurement
+   vs line fitting will be calculated, and the residual error is normalized
+   with each measurement. The test failes if residual error is bigger than
+   2dB.
+
+   This test will be robust to background noise as long as it is persistent.
+   But background noise which appears shortly with enough strength can
+   mess up the result.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <cutils/log.h>
+#include "LinearityTest.h"
+
+#define LOG_TAG "LinearityTestRms"
+
+// vectorDot, vectorNorm, and solveLeastSquares
+// copied from frameworks/base/libs/ui/Input.cpp
+
+static inline float vectorDot(const float* a, const float* b, uint32_t m) {
+    float r = 0;
+    while (m--) {
+        r += *(a++) * *(b++);
+    }
+    return r;
+}
+
+static inline float vectorNorm(const float* a, uint32_t m) {
+    float r = 0;
+    while (m--) {
+        float t = *(a++);
+        r += t * t;
+    }
+    return sqrtf(r);
+}
+
+/**
+ * Solves a linear least squares problem to obtain a N degree polynomial that fits
+ * the specified input data as nearly as possible.
+ *
+ * Returns true if a solution is found, false otherwise.
+ *
+ * The input consists of two vectors of data points X and Y with indices 0..m-1.
+ * The output is a vector B with indices 0..n-1 that describes a polynomial
+ * that fits the data, such the sum of abs(Y[i] - (B[0] + B[1] X[i] + B[2] X[i]^2 ... B[n] X[i]^n))
+ * for all i between 0 and m-1 is minimized.
+ *
+ * That is to say, the function that generated the input data can be approximated
+ * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
+ *
+ * The coefficient of determination (R^2) is also returned to describe the goodness
+ * of fit of the model for the given data.  It is a value between 0 and 1, where 1
+ * indicates perfect correspondence.
+ *
+ * This function first expands the X vector to a m by n matrix A such that
+ * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n.
+ *
+ * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q
+ * and an m by n upper triangular matrix R.  Because R is upper triangular (lower
+ * part is all zeroes), we can simplify the decomposition into an m by n matrix
+ * Q1 and a n by n matrix R1 such that A = Q1 R1.
+ *
+ * Finally we solve the system of linear equations given by R1 B = (Qtranspose Y)
+ * to find B.
+ *
+ * For efficiency, we lay out A and Q column-wise in memory because we frequently
+ * operate on the column vectors.  Conversely, we lay out R row-wise.
+ *
+ * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
+ * http://en.wikipedia.org/wiki/Gram-Schmidt
+ */
+static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32_t n,
+        float* outB, float* outDet) {
+#if DEBUG_LEAST_SQUARES
+    LOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s", int(m), int(n),
+            vectorToString(x, m).string(), vectorToString(y, m).string());
+#endif
+
+    // Expand the X vector to a matrix A.
+    float a[n][m]; // column-major order
+    for (uint32_t h = 0; h < m; h++) {
+        a[0][h] = 1;
+        for (uint32_t i = 1; i < n; i++) {
+            a[i][h] = a[i - 1][h] * x[h];
+        }
+    }
+#if DEBUG_LEAST_SQUARES
+    LOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
+#endif
+
+    // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
+    float q[n][m]; // orthonormal basis, column-major order
+    float r[n][n]; // upper triangular matrix, row-major order
+    for (uint32_t j = 0; j < n; j++) {
+        for (uint32_t h = 0; h < m; h++) {
+            q[j][h] = a[j][h];
+        }
+        for (uint32_t i = 0; i < j; i++) {
+            float dot = vectorDot(&q[j][0], &q[i][0], m);
+            for (uint32_t h = 0; h < m; h++) {
+                q[j][h] -= dot * q[i][h];
+            }
+        }
+
+        float norm = vectorNorm(&q[j][0], m);
+        if (norm < 0.000001f) {
+            // vectors are linearly dependent or zero so no solution
+#if DEBUG_LEAST_SQUARES
+            LOGD("  - no solution, norm=%f", norm);
+#endif
+            return false;
+        }
+
+        float invNorm = 1.0f / norm;
+        for (uint32_t h = 0; h < m; h++) {
+            q[j][h] *= invNorm;
+        }
+        for (uint32_t i = 0; i < n; i++) {
+            r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
+        }
+    }
+#if DEBUG_LEAST_SQUARES
+    LOGD("  - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
+    LOGD("  - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
+
+    // calculate QR, if we factored A correctly then QR should equal A
+    float qr[n][m];
+    for (uint32_t h = 0; h < m; h++) {
+        for (uint32_t i = 0; i < n; i++) {
+            qr[i][h] = 0;
+            for (uint32_t j = 0; j < n; j++) {
+                qr[i][h] += q[j][h] * r[j][i];
+            }
+        }
+    }
+    LOGD("  - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
+#endif
+
+    // Solve R B = Qt Y to find B.  This is easy because R is upper triangular.
+    // We just work from bottom-right to top-left calculating B's coefficients.
+    for (uint32_t i = n; i-- != 0; ) {
+        outB[i] = vectorDot(&q[i][0], y, m);
+        for (uint32_t j = n - 1; j > i; j--) {
+            outB[i] -= r[i][j] * outB[j];
+        }
+        outB[i] /= r[i][i];
+    }
+#if DEBUG_LEAST_SQUARES
+    LOGD("  - b=%s", vectorToString(outB, n).string());
+#endif
+
+    // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
+    // SSerr is the residual sum of squares (squared variance of the error),
+    // and SStot is the total sum of squares (squared variance of the data).
+    float ymean = 0;
+    for (uint32_t h = 0; h < m; h++) {
+        ymean += y[h];
+    }
+    ymean /= m;
+
+    float sserr = 0;
+    float sstot = 0;
+    for (uint32_t h = 0; h < m; h++) {
+        float err = y[h] - outB[0];
+        float term = 1;
+        for (uint32_t i = 1; i < n; i++) {
+            term *= x[h];
+            err -= term * outB[i];
+        }
+        sserr += err * err;
+        float var = y[h] - ymean;
+        sstot += var * var;
+    }
+    *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
+#if DEBUG_LEAST_SQUARES
+    LOGD("  - sserr=%f", sserr);
+    LOGD("  - sstot=%f", sstot);
+    LOGD("  - det=%f", *outDet);
+#endif
+    return true;
+}
+
+/* calculate RMS of given sample with numSamples of length */
+float calcRms(short* pcm, int numSamples)
+{
+    float energy = 0.0f;
+    for(int i = 0; i < numSamples; i++) {
+        float sample = (float)pcm[i];
+        energy += (sample * sample);
+    }
+    return sqrtf(energy);
+}
+
+/* There are numSignals int16 signals in pcms.  sampleCounts is an
+   integer array of length numSignals containing their respective
+   lengths in samples.  They are all sampled at sampleRate.  The pcms
+   are ordered by increasing stimulus level.  The level steps between
+   successive stimuli were of size dbStepSize dB.
+   The maximum deviation in linearity found
+   (in dB) is returned in maxDeviation.  The function returns 1 if
+   the measurements could be made, or a negative number that
+   indicates the error, as defined in LinearityTest.h */
+int linearityTestRms(short** pcms, int* sampleCounts, int numSignals,
+                  float sampleRate, float dbStepSize,
+                  float* maxDeviation) {
+    if (!(pcms && sampleCounts)) {
+        return ERROR_INPUT_SIGNAL_MISSING;
+    }
+    if (numSignals < 2) {
+      return ERROR_INPUT_SIGNAL_NUMBERS;
+    }
+    if (sampleRate <= 4000.0) {
+      return ERROR_SAMPLE_RATE_TOO_LOW;
+    }
+    if (dbStepSize <= 0.0) {
+        return ERROR_NEGATIVE_STEP_SIZE;
+    }
+
+    float* levels = new float[numSignals];
+    levels[0] = 1.0f;
+    float stepInMag = powf(10.0f, dbStepSize/20.0f);
+    for(int i = 1; i < numSignals; i++) {
+        levels[i] = levels[i - 1] * stepInMag;
+    }
+
+    float* rmsValues = new float[numSignals];
+    for (int i = 0; i < numSignals; i++) {
+        rmsValues[i] = calcRms(pcms[i], sampleCounts[i]);
+    }
+    const int NO_COEFFS = 2; // only line fitting
+    float coeffs[NO_COEFFS];
+    float outDet;
+    if(!solveLeastSquares(levels, rmsValues, numSignals, NO_COEFFS,
+                          coeffs, &outDet)) {
+        ALOGI(" solveLeastSquares fails with det %f", outDet);
+        return ERROR_LINEAR_FITTING;
+    }
+    ALOGI(" coeffs offset %f linear %f", coeffs[0], coeffs[1]);
+    float maxDev = 0.0f;
+    for(int i = 0; i < numSignals; i++) {
+        float residue = coeffs[0] + coeffs[1] * levels[i] - rmsValues[i];
+        // to make devInDb positive, add measured value itself
+        // then normalize
+        float devInDb = 20.0f * log10f((fabs(residue) + rmsValues[i])
+                                       / rmsValues[i]);
+        ALOGI(" %d-th residue %f dB", i, devInDb);
+        if (devInDb > maxDev) {
+            maxDev = devInDb;
+        }
+    }
+    *maxDeviation = maxDev;
+
+    delete[] levels;
+    delete[] rmsValues;
+
+    return 1;
+}
diff --git a/apps/CtsVerifier/jni/audioquality/Wrapper.cpp b/apps/CtsVerifier/jni/audioquality/Wrapper.cpp
index bee15c6..438f0d8 100644
--- a/apps/CtsVerifier/jni/audioquality/Wrapper.cpp
+++ b/apps/CtsVerifier/jni/audioquality/Wrapper.cpp
@@ -57,6 +57,12 @@
             JNIEnv *env, jobject obj,
             jobjectArray jpcms,
             jfloat sampleRate, jfloat dbStepSize, jint referenceStim);
+
+    JNIEXPORT jfloat JNICALL
+        Java_com_android_cts_verifier_audioquality_Native_linearityTestRms(
+            JNIEnv *env, jobject obj,
+            jobjectArray jpcms,
+            jfloat sampleRate, jfloat dbStepSize);
 };
 
 /* Returns an array of sinusoidal samples.
@@ -241,3 +247,41 @@
 
     return maxDeviation;
 }
+
+
+/* Return maximum deviation from linearity in dB.
+   On failure returns:
+      -1.0 The input signals or sample counts are missing.
+      -2.0 The number of input signals is < 2.
+      -3.0 The specified sample rate is <= 4000.0
+      -4.0 The dB step size for the increase in stimulus level is <= 0.0
+      -6.0 One or more of the stimuli is too short in duration.
+*/
+JNIEXPORT jfloat JNICALL
+    Java_com_android_cts_verifier_audioquality_Native_linearityTestRms(
+        JNIEnv *env, jobject obj,
+        jobjectArray jpcms,
+        jfloat sampleRate, jfloat dbStepSize) {
+    int numSignals = env->GetArrayLength(jpcms);
+    int *sampleCounts = new int[numSignals];
+    short **pcms = new shortPtr[numSignals];
+    jshortArray ja;
+    for (int i = 0; i < numSignals; i++) {
+        ja = (jshortArray) env->GetObjectArrayElement(jpcms, i);
+        sampleCounts[i] = env->GetArrayLength(ja);
+        pcms[i] = new short[sampleCounts[i]];
+        env->GetShortArrayRegion(ja, 0, sampleCounts[i], pcms[i]);
+    }
+
+    float maxDeviation = -1.0;
+    int ret = linearityTestRms(pcms, sampleCounts, numSignals,
+            sampleRate, dbStepSize, &maxDeviation);
+    delete[] sampleCounts;
+    for (int i = 0; i < numSignals; i++) {
+        delete[] pcms[i];
+    }
+    delete[] pcms;
+    if (ret < 1) return ret;
+
+    return maxDeviation;
+}
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
index 51fd0c5..83f5c17 100644
--- 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
@@ -36,7 +36,7 @@
     AndroidBitmap_getInfo(env, inputBitmap, &inputInfo);
     if (inputInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888 &&
         inputInfo.format != ANDROID_BITMAP_FORMAT_RGB_565) {
-        LOGE("Only RGBA_8888 and RGB_565 bitmaps are supported, type was %d.",
+        ALOGE("Only RGBA_8888 and RGB_565 bitmaps are supported, type was %d.",
              inputInfo.format);
     }
 
@@ -52,7 +52,7 @@
             reinterpret_cast<void**>(&inputBuffer));
 
     if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-        LOGE("Unable to lock input bitmap");
+        ALOGE("Unable to lock input bitmap");
     }
 
     uint8_t *outputImage = NULL;
@@ -107,7 +107,7 @@
 
     result = AndroidBitmap_unlockPixels(env, inputBitmap);
     if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-        LOGE("Unable to unlock input bitmap");
+        ALOGE("Unable to unlock input bitmap");
     }
 
     if (freeInputRGBA) {
@@ -201,14 +201,14 @@
                 reinterpret_cast<void**>(&outputBuffer) );
 
         if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-            LOGE("Unable to lock output bitmap");
+            ALOGE("Unable to lock output bitmap");
         }
 
         memcpy(outputBuffer, outputImage, outputWidth * outputHeight * 4);
 
         result = AndroidBitmap_unlockPixels(env, outputBitmap);
         if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-            LOGE("Unable to unlock output bitmap");
+            ALOGE("Unable to unlock output bitmap");
         }
 
         // Write new Bitmap reference into mDebugOutput class member
diff --git a/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp b/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp
index 63bce63..46b8cc8 100644
--- a/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp
+++ b/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp
@@ -236,7 +236,7 @@
         delete[] gradientDirection;
 
     } else {
-        LOGE("Not a color image!");
+        ALOGE("Not a color image!");
     }
 
     delete[] edgeMap;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java
index 755b62d..af389a6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java
@@ -134,7 +134,7 @@
         fillAdapter();
         mList.setAdapter(mAdapter);
         mList.setOnItemClickListener(this);
-        checkNotSilent();
+        adjustVolume();
     }
 
     @Override
@@ -142,18 +142,18 @@
         super.onResume();
         mAdapter.notifyDataSetChanged(); // Update List UI
         setVolumeControlStream(AudioManager.STREAM_MUSIC);
-        checkNotSilent();
+        adjustVolume();
     }
 
-    private void checkNotSilent() {
+    private void adjustVolume() {
         AudioManager mgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
         mgr.setStreamMute(PLAYBACK_STREAM, false);
         int volume = mgr.getStreamVolume(PLAYBACK_STREAM);
         int max = mgr.getStreamMaxVolume(PLAYBACK_STREAM);
+        int target = (max * 2) / 3;
         Log.i(TAG, "Volume " + volume + ", max " + max);
-        if (volume <= max / 10) {
-            // Volume level is silent or very quiet; increase to two-thirds
-            mgr.setStreamVolume(PLAYBACK_STREAM, (max * 2) / 3, AudioManager.FLAG_SHOW_UI);
+        if (volume != target) {
+            mgr.setStreamVolume(PLAYBACK_STREAM, target, AudioManager.FLAG_SHOW_UI);
         }
     }
 
@@ -188,6 +188,7 @@
     // Implements AdapterView.OnItemClickListener
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         if (mRunningExperiment) return;
+        adjustVolume();
         runExperiment(position, false);
     }
 
@@ -207,6 +208,7 @@
 
     // Implements View.OnClickListener:
     public void onClick(View v) {
+        adjustVolume();
         if (v == mCalibrateButton) {
             Intent intent = new Intent(this, CalibrateVolumeActivity.class);
             startActivity(intent);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/Native.java b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/Native.java
index 87b11d1..cdb3e25 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/Native.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/Native.java
@@ -31,6 +31,8 @@
             float sampleRate);
     public native float linearityTest(short[][] pcms,
         float sampleRate, float dbStepSize, int referenceStim);
+    public native float linearityTestRms(short[][] pcms,
+        float sampleRate, float dbStepSize);
 
     // The following indexes must match those in wrapper.cc
     public static final int MEASURE_RMS_RMS = 0;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/GainLinearityExperiment.java b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/GainLinearityExperiment.java
index 05f1602..225df1a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/GainLinearityExperiment.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/GainLinearityExperiment.java
@@ -66,9 +66,8 @@
         for (int i = 0; i < LEVELS; i++) {
             pcms[i] = Utils.byteToShortArray(record[i]);
         }
-        // We specify the middle stimulus (LEVELS / 2) as the "reference":
-        float deviation = mNative.linearityTest(pcms, AudioQualityVerifierActivity.SAMPLE_RATE,
-                DB_STEP_SIZE, LEVELS / 2);
+        float deviation = mNative.linearityTestRms(pcms, AudioQualityVerifierActivity.SAMPLE_RATE,
+                DB_STEP_SIZE);
         if (deviation < 0.0f) {
             setScore(getString(R.string.aq_fail));
             setReport(String.format(getString(R.string.aq_linearity_report_error), deviation));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/SpectrumShapeExperiment.java b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/SpectrumShapeExperiment.java
index 148fb47..df7919e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/SpectrumShapeExperiment.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/experiments/SpectrumShapeExperiment.java
@@ -33,7 +33,7 @@
     private static final int DURATION = 3;
 
     public SpectrumShapeExperiment() {
-        super(true);
+        super(false); // disable temporarily
     }
 
     @Override
diff --git a/development/ide/eclipse/.classpath b/development/ide/eclipse/.classpath
index 47e0025..c76f293 100644
--- a/development/ide/eclipse/.classpath
+++ b/development/ide/eclipse/.classpath
@@ -58,6 +58,8 @@
     <classpathentry kind="src" path="cts/tests/tests/webkit/src"/>
     <classpathentry kind="src" path="cts/tests/tests/widget/src"/>
     <classpathentry kind="src" path="cts/tools/cts-api-coverage/src"/>
+    <classpathentry kind="src" path="cts/tools/cts-java-scanner/src"/>
+    <classpathentry kind="src" path="cts/tools/cts-java-scanner-doclet/src"/>
     <classpathentry kind="src" path="cts/tools/cts-native-scanner/src"/>
     <classpathentry kind="src" path="cts/tools/cts-reference-app-lib/src"/>
     <classpathentry kind="src" path="cts/tools/cts-xml-generator/src"/>
diff --git a/tests/appsecurity-tests/Android.mk b/tests/appsecurity-tests/Android.mk
index b5ce83c..4dd8d5c 100644
--- a/tests/appsecurity-tests/Android.mk
+++ b/tests/appsecurity-tests/Android.mk
@@ -16,8 +16,6 @@
 
 include $(CLEAR_VARS)
 
-#LOCAL_TEST_TYPE := hostSideOnly
-
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -25,8 +23,9 @@
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt ddmlib-prebuilt junit
 
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_CTS_TEST_PACKAGE := android.tests.appsecurity
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
-
diff --git a/tests/assets/webkit/jsform.html b/tests/assets/webkit/jsform.html
index 1781194..ce55498 100644
--- a/tests/assets/webkit/jsform.html
+++ b/tests/assets/webkit/jsform.html
@@ -24,7 +24,7 @@
             }
         }
     </script>
-    <body onload="window.setTimeout(function() { fireSubmit(); }, 0);">
+    <body onload="window.setTimeout(function() { fireSubmit(); }, 500);">
         javascript form test
         <form id="formId" action="test.html#result" method="post">
             <input type="hidden" name="foo" value="bar" />
diff --git a/tests/config_demo/data/case_rep/APICheckTest_java5.apk b/tests/config_demo/data/case_rep/APICheckTest_java5.apk
deleted file mode 100644
index fcb51c4..0000000
--- a/tests/config_demo/data/case_rep/APICheckTest_java5.apk
+++ /dev/null
Binary files differ
diff --git a/tests/config_demo/data/case_rep/APICheckTest_java6.apk b/tests/config_demo/data/case_rep/APICheckTest_java6.apk
deleted file mode 100644
index 76c8f74..0000000
--- a/tests/config_demo/data/case_rep/APICheckTest_java6.apk
+++ /dev/null
Binary files differ
diff --git a/tests/config_demo/data/case_rep/DeviceInforCollector.apk b/tests/config_demo/data/case_rep/DeviceInforCollector.apk
deleted file mode 100644
index 24de83f..0000000
--- a/tests/config_demo/data/case_rep/DeviceInforCollector.apk
+++ /dev/null
Binary files differ
diff --git a/tests/config_demo/data/host_config.xml b/tests/config_demo/data/host_config.xml
deleted file mode 100644
index 4e4cb9a..0000000
--- a/tests/config_demo/data/host_config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<HostConfiguration version="1.0">
-    <Repository>
-        <!-- Specific OEM test plan directory (optional) -->
-        <TestPlan path="plan_rep" />
-        <!-- Specific OEM test case directory (optional) -->
-        <TestCase path="case_rep" />
-        <!-- Specific OEM test result directory (optional) -->
-        <TestResult path="result_rep" />
-    </Repository>
-</HostConfiguration>
diff --git a/tests/config_demo/data/plan_rep/README b/tests/config_demo/data/plan_rep/README
deleted file mode 100644
index 2f36f40..0000000
--- a/tests/config_demo/data/plan_rep/README
+++ /dev/null
@@ -1,17 +0,0 @@
-Copyright (C) 2008 The Android Open Source Project
-
-Licensed under the Apache Licence, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-This directory would be the repository of the test plans.
-
-For detailed descriptions, please refer to the architecture document.
diff --git a/tests/config_demo/data/result_rep/cts_result.xsl b/tests/config_demo/data/result_rep/cts_result.xsl
deleted file mode 100644
index 9c9c82a..0000000
--- a/tests/config_demo/data/result_rep/cts_result.xsl
+++ /dev/null
@@ -1,339 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> ]>
-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
-    <xsl:template match="/">
-       
-        <html>
-            <STYLE type="text/css">
-                    .plan { background-color : #9acd32 }
-                    .head { font-size : 30; background-color : #A8A6A6 }
-                    .head1 { font-size : 20; background-color : #A8A6A6 }
-                    .lgreen {background-color : #9acd32}
-                    .pass {background-color : #00ff00}
-                    .failed {background-color : #ff0000}
-                    .timeout {background-color : #febf00}
-                    .notrun {background-color : #C6C3C3}
-                    .gray {background-color : #C6C3C3}
-            </STYLE>
-            <body>
-                <p class="head">CTS Test result</p>
-
-                <!-- plan information -->
-                <TABLE >
-                    <TR class="plan">
-                        <TD>Plan name</TD>
-                        <TD>Start time</TD>
-                        <TD>End time</TD>
-                        <TD>Version</TD>
-                    </TR>
-                    <TR>
-                        <TD>
-                            <xsl:value-of select="TestResult/@testPlan"/>
-                        </TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/@starttime"/>
-                        </TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/@endtime"/>
-                        </TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/@version"/>
-                        </TD>
-                    </TR>
-                </TABLE>
-                <!-- Device infor -->
-                <p class="head1">Test Device information</p>
-                <TABLE >
-                    <TR>
-                        <TD class="lgreen">Device Make</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@buildName"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Build model</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@deviceID"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Firmware Version</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@buildVersion"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Firmware Build Number</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@buildID"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Android Platform Version</TD>
-                        <TD>
-                            <xsl:value-of
-                                select="TestResult/DeviceInfo/BuildInfo/@androidPlatformVersion"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Supported Locales</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@locales"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Screen size</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/Screen/@resolution"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Phone number</TD>
-                        <TD>
-                            <xsl:value-of
-                                select="TestResult/DeviceInfo/PhoneSubInfo/@subscriberId"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">x dpi</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@Xdpi"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">y dpi</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@Ydpi"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Touch</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@touch"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Navigation</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@navigation"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Keypad</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@keypad"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">Network</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@network"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">IMEI</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@imei"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="lgreen">IMSI</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@imsi"/>
-                        </TD>
-                    </TR>
-                </TABLE>
-                <!-- Summary -->
-                <p class="head1">Summary</p>
-                <TABLE >
-                    <TR>
-                        <TD class="pass">pass</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/Summary/@pass"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="failed">failed</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/Summary/@failed"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="timeout">timeout</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/Summary/@timeout"/>
-                        </TD>
-                    </TR>
-                    <TR>
-                        <TD class="notrun">notrun</TD>
-                        <TD>
-                            <xsl:value-of select="TestResult/Summary/@notrun"/>
-                        </TD>
-                    </TR>
-                </TABLE>
-                <!-- test package -->
-                <xsl:for-each select="TestResult/TestPackage">
-                    <p class="head1">
-                        TestPackage:
-                        <xsl:value-of select="@name"/>
-                    </p>
-
-                    <TABLE border="0.1">
-                        <!-- level 1 test suite -->
-                        <xsl:for-each select="TestSuite">
-                            <TR>
-                                <TD class="gray">
-                                    <xsl:value-of select="@name"/>
-                                </TD>
-                                <TD class="gray"></TD>
-                                <TD class="gray"></TD>
-                                <TD class="gray"></TD>
-                                <TD class="gray"></TD>
-                            </TR>
-                            <xsl:for-each select="TestCase">
-                                <TR>
-                                    <TD></TD>
-                                    <TD class="gray">
-                                        <xsl:value-of select="@name"/>
-                                    </TD>
-                                    <TD class="gray"></TD>
-                                    <TD class="gray"></TD>
-                                    <TD class="gray"></TD>
-                                </TR>
-                                <xsl:for-each select="Test">
-                                    <TR>
-                                        <TD></TD>
-                                        <TD></TD>
-
-                                            <xsl:if test="@result='pass'">
-                                                <TD class="pass">
-                                                    <xsl:value-of select="@name"/>
-                                                </TD>
-                                                <TD class="pass">
-                                                    <xsl:value-of select="@result"/>
-                                                </TD>
-                                            </xsl:if>
-                                            
-                                            <xsl:if test="@result='fail'">
-                                                <TD class="failed">
-                                                    <xsl:value-of select="@name"/>
-                                                </TD>
-                                                <TD class="failed">
-                                                    <xsl:value-of select="@result"/>
-                                                </TD>
-                                            </xsl:if>
-    
-                                            <xsl:if test="@result='timeout'">
-                                                <TD class="timeout">
-                                                    <xsl:value-of select="@name"/>
-                                                </TD>
-                                                <TD class="timeout">
-                                                    <xsl:value-of select="@result"/>
-                                                </TD>
-                                            </xsl:if>
-
-                                            <xsl:if test="@result='notrun'">
-                                                <TD class="notrun">
-                                                    <xsl:value-of select="@name"/>
-                                                </TD>
-                                                <TD class="notrun">
-                                                    <xsl:value-of select="@result"/>
-                                                </TD>
-                                            </xsl:if>
-
-                                        <TD></TD>
-                                    </TR>
-                                </xsl:for-each>
-                            </xsl:for-each>
-                            <!-- level 2 test suite -->
-                            <xsl:for-each select="TestSuite">
-                                <TR>
-                                    <TD></TD>
-                                    <TD class="gray">
-                                        <xsl:value-of select="@name"/>
-                                    </TD>
-                                    <TD class="gray"></TD>
-                                    <TD class="gray"></TD>
-                                    <TD class="gray"></TD>
-                                </TR>   
-                                    <xsl:for-each select="TestCase">
-                                        <TR>
-                                            <TD></TD>
-                                            <TD></TD>
-                                            <TD class="gray">
-                                                <xsl:value-of select="@name"/>
-                                            </TD>
-                                            <TD class="gray"></TD>
-                                            <TD class="gray"></TD>
-                                        </TR>
-                                        <xsl:for-each select="Test">
-                                            <TR>
-                                                <TD></TD>
-                                                <TD></TD>
-                                                <TD></TD>
-                                                
-                                                <xsl:if test="@result='pass'">
-                                                    <TD class="pass">
-                                                        <xsl:value-of select="@name"/>
-                                                    </TD>
-                                                    <TD class="pass">
-                                                        <xsl:value-of select="@result"/>
-                                                    </TD>
-                                                </xsl:if>
-                                            
-                                                <xsl:if test="@result='fail'">
-                                                    <TD class="failed">
-                                                        <xsl:value-of select="@name"/>
-                                                    </TD>
-                                                    <TD class="failed">
-                                                        <xsl:value-of select="@result"/>
-                                                    </TD>
-                                                </xsl:if>
-        
-                                                <xsl:if test="@result='timeout'">
-                                                    <TD class="timeout">
-                                                        <xsl:value-of select="@name"/>
-                                                    </TD>
-                                                    <TD class="timeout">
-                                                        <xsl:value-of select="@result"/>
-                                                    </TD>
-                                                </xsl:if>
-
-                                                <xsl:if test="@result='notrun'">
-                                                    <TD class="notrun">
-                                                        <xsl:value-of select="@name"/>
-                                                    </TD>
-                                                    <TD class="notrun">
-                                                        <xsl:value-of select="@result"/>
-                                                    </TD>
-                                                </xsl:if>
-                                                
-                                            </TR>
-                                        </xsl:for-each>
-                                    </xsl:for-each>
-                                
-                            </xsl:for-each>
-                        </xsl:for-each>
-                    </TABLE>
-                </xsl:for-each>
-                <!-- end test package -->
-            </body>
-        </html>
-    </xsl:template>
-</xsl:stylesheet>
diff --git a/tests/jni/android_net_cts_NetlinkSocket.cpp b/tests/jni/android_net_cts_NetlinkSocket.cpp
index 1e671c6..f2fc38f 100644
--- a/tests/jni/android_net_cts_NetlinkSocket.cpp
+++ b/tests/jni/android_net_cts_NetlinkSocket.cpp
@@ -31,7 +31,7 @@
 {
     int sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
     if (sock == -1) {
-        LOGE("Can't create socket %s", strerror(errno));
+        ALOGE("Can't create socket %s", strerror(errno));
         jclass SocketException = env->FindClass("java/net/SocketException");
         env->ThrowNew(SocketException, "Can't create socket");
         return;
diff --git a/tests/src/android/webkit/cts/CtsTestServer.java b/tests/src/android/webkit/cts/CtsTestServer.java
index 6d3bfe6..69be105 100755
--- a/tests/src/android/webkit/cts/CtsTestServer.java
+++ b/tests/src/android/webkit/cts/CtsTestServer.java
@@ -554,15 +554,20 @@
                     "  <head>" +
                     "    <title>Waiting</title>" +
                     "    <script>" +
-                    "      function updateTitle() { document.title = \"Done\"; }" +
-                    "      window.applicationCache.onnoupdate = updateTitle;" +
-                    "      window.applicationCache.oncached = updateTitle;" +
-                    "      window.applicationCache.onupdateready = updateTitle;" +
-                    "      window.applicationCache.onobsolete = updateTitle;" +
-                    "      window.applicationCache.onerror = updateTitle;" +
+                    "      function updateTitle(x) { document.title = x; }" +
+                    "      window.applicationCache.onnoupdate = " +
+                    "          function() { updateTitle(\"onnoupdate Callback\"); };" +
+                    "      window.applicationCache.oncached = " +
+                    "          function() { updateTitle(\"oncached Callback\"); };" +
+                    "      window.applicationCache.onupdateready = " +
+                    "          function() { updateTitle(\"onupdateready Callback\"); };" +
+                    "      window.applicationCache.onobsolete = " +
+                    "          function() { updateTitle(\"onobsolete Callback\"); };" +
+                    "      window.applicationCache.onerror = " +
+                    "          function() { updateTitle(\"onerror Callback\"); };" +
                     "    </script>" +
                     "  </head>" +
-                    "  <body>AppCache test</body>" +
+                    "  <body onload=\"updateTitle('Loaded');\">AppCache test</body>" +
                     "</html>"));
         } else if (path.equals(APPCACHE_MANIFEST_PATH)) {
             response = createResponse(HttpStatus.SC_OK);
diff --git a/tests/src/android/webkit/cts/WaitForLoadUrl.java b/tests/src/android/webkit/cts/WaitForLoadUrl.java
deleted file mode 100644
index 7ccd6d2..0000000
--- a/tests/src/android/webkit/cts/WaitForLoadUrl.java
+++ /dev/null
@@ -1,314 +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.webkit.cts;
-
-import android.cts.util.PollingCheck;
-import android.graphics.Bitmap;
-import android.graphics.Picture;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.webkit.WebChromeClient;
-import android.webkit.WebView;
-import android.webkit.WebView.PictureListener;
-import android.webkit.WebViewClient;
-
-import junit.framework.Assert;
-
-/**
- * This class is used to determine when a page has finished loading.
- *
- * initializeWebView sets a WebViewClient, WebChromeClient, and a
- * PictureListener. If a tests provides its own handler, it must call
- * the corresponding WaitForLoadUrl.on* function.
- *
- * This class only really works correctly with a single WebView active because
- * it acts as a singleton.
- */
-class WaitForLoadUrl extends WebViewClient {
-    private static final WaitForLoadUrl sInstance = new WaitForLoadUrl();
-
-    /**
-     * The maximum time, in milliseconds (10 seconds) to wait for a load
-     * to be triggered.
-     */
-    private static final long LOAD_TIMEOUT = 10000;
-
-    /**
-     * Set to true after onPageFinished is called.
-     */
-    private boolean mLoaded;
-
-    /**
-     * Set to true after onNewPicture is called. Reset when onPageFinished
-     * is called.
-     */
-    private boolean mNewPicture;
-
-    /**
-     * The progress, in percentage, of the page load. Valid values are between
-     * 0 and 100.
-     */
-    private int mProgress;
-
-    /**
-     * Private constructor enforces singleton behavior.
-     */
-    private WaitForLoadUrl() {
-    }
-
-    /**
-     * Returns the singleton instance.
-     */
-    public static WaitForLoadUrl getInstance() {
-        return sInstance;
-    }
-
-    /**
-     * Called from WaitForNewPicture, this is used to indicate that
-     * the page has been drawn.
-     */
-    synchronized public void onNewPicture() {
-        mNewPicture = true;
-        this.notifyAll();
-    }
-
-    /**
-     * Called from WaitForLoadedClient, this is used to clear the picture
-     * draw state so that draws before the URL begins loading don't count.
-     */
-    synchronized public void onPageStarted() {
-        mNewPicture = false; // Earlier paints won't count.
-    }
-
-    /**
-     * Called from WaitForLoadedClient, this is used to indicate that
-     * the page is loaded, but not drawn yet.
-     */
-    synchronized public void onPageFinished() {
-        mLoaded = true;
-        this.notifyAll();
-    }
-
-    /**
-     * Called from the WebChrome client, this sets the current progress
-     * for a page.
-     * @param progress The progress made so far between 0 and 100.
-     */
-    synchronized public void onProgressChanged(int progress) {
-        mProgress = progress;
-        this.notifyAll();
-    }
-
-    /**
-     * Sets the WebViewClient, WebChromeClient, and PictureListener for a
-     * WebView to prepare it for the waitForLoadComplete call. If one
-     * of these handlers needs to be changed, the onPageFinished,
-     * onProgressChanged, or onNewPicture must be called from the callback
-     * class.
-     */
-    public void initializeWebView(InstrumentationTestCase test,
-            final WebView view) {
-        Runnable setup = new Runnable() {
-            @Override
-            public void run() {
-                view.setWebViewClient(new WaitForLoadedClient());
-                view.setPictureListener(new WaitForNewPicture());
-                view.setWebChromeClient(new WaitForProgressClient());
-            }
-        };
-        if (isUiThread()) {
-            setup.run();
-        } else {
-            try {
-                test.runTestOnUiThread(setup);
-            } catch (Throwable t) {
-                Assert.fail("Error initializing WebView for waitForLoadUrl");
-            }
-        }
-        clearLoad();
-    }
-
-    /**
-     * Called whenever a load has been completed so that a subsequent call to
-     * waitForLoadComplete doesn't return immediately. This must be called only
-     * after onPageFinished is received for a loadUrl call or else a callback
-     * will change the state before a subsequent load begins and
-     * waitForLoadComplete will not work properly. Normally this call is not
-     * necessary as it is automatically called as part of waitFor.
-     */
-    synchronized public void clearLoad() {
-        mLoaded = false;
-        mNewPicture = false;
-        mProgress = 0;
-    }
-
-    /**
-     * Wait for a page onPageFinished, onNewPicture and
-     * onProgressChange to reach 100. If that does not occur
-     * before LOAD_TIMEOUT expires there will be a test failure.
-     *
-     * This call may be made on the UI thread or a test thread.
-     * @see WaitForLoadUrl#initializeWebView
-     */
-    public void waitForLoadComplete(WebView webView) {
-        waitFor(webView, new WaitCheck() {
-            @Override
-            public boolean isDone() {
-                return mLoaded && mNewPicture && mProgress == 100;
-            }
-        });
-    }
-
-    /**
-     * Waits for the waitCheck condition to be true or the test times out.
-     * The load state is cleared after waiting.
-     * @param webView The WebView for which the test is running.
-     * @param waitCheck Contains the condition to be checked.
-     */
-    private void waitFor(WebView webView, WaitCheck waitCheck) {
-        if (isUiThread()) {
-            waitOnUiThread(webView, waitCheck);
-        } else {
-            waitOnTestThread(waitCheck);
-        }
-        clearLoad();
-    }
-
-    /**
-     * Uses a polling mechanism, while pumping messages to check when the
-     * waitCheck condition is true.
-     * @param webView The WebView for which the test is running.
-     * @param waitCheck Contains the condition to be checked.
-     */
-    private void waitOnUiThread(final WebView webView,
-            final WaitCheck waitCheck) {
-        new PollingCheck(LOAD_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                pumpMessages(webView);
-                synchronized(this) {
-                    return waitCheck.isDone();
-                }
-            }
-        }.run();
-    }
-
-    /**
-     * Uses a wait/notify to check when the waitCheck condition is true.
-     * @param webView The WebView for which the test is running.
-     * @param waitCheck Contains the condition to be checked.
-     */
-    private synchronized void waitOnTestThread(WaitCheck waitCheck) {
-        try {
-            long waitEnd = SystemClock.uptimeMillis() + LOAD_TIMEOUT;
-            long timeRemaining = LOAD_TIMEOUT;
-            while (!waitCheck.isDone() && timeRemaining > 0) {
-                this.wait(timeRemaining);
-                timeRemaining = waitEnd - SystemClock.uptimeMillis();
-            }
-        } catch (InterruptedException e) {
-            // We'll just drop out of the loop and fail
-        }
-        Assert.assertTrue("Load failed to complete before timeout",
-                waitCheck.isDone());
-    }
-
-    /**
-     * Pumps all currently-queued messages in the UI thread and then exits.
-     * This is useful to force processing while running tests in the UI thread.
-     */
-    private static void pumpMessages(WebView webView) {
-        class ExitLoopException extends RuntimeException {
-        }
-
-        // Force loop to exit when processing this. Loop.quit() doesn't
-        // work because this is the main Loop.
-        webView.getHandler().post(new Runnable() {
-            @Override
-            public void run() {
-                throw new ExitLoopException(); // exit loop!
-            }
-        });
-        try {
-            // Pump messages until our message gets through.
-            Looper.loop();
-        } catch (ExitLoopException e) {
-        }
-    }
-
-    /**
-     * Returns true if the current thread is the UI thread based on the
-     * Looper.
-     */
-    private static boolean isUiThread() {
-        return (Looper.myLooper() == Looper.getMainLooper());
-    }
-
-    private interface WaitCheck {
-        public boolean isDone();
-    }
-
-    /**
-     * A WebChromeClient used to capture the onProgressChanged for use
-     * in waitFor functions. If a test must override the WebChromeClient,
-     * it can derive from this class or call WaitForLoadUrl.onProgressChanged
-     * directly.
-     */
-    public static class WaitForProgressClient extends WebChromeClient {
-        @Override
-        public void onProgressChanged(WebView view, int newProgress) {
-            super.onProgressChanged(view, newProgress);
-            WaitForLoadUrl.getInstance().onProgressChanged(newProgress);
-        }
-    }
-
-    /**
-     * A WebViewClient that captures the onPageFinished for use in
-     * waitFor functions. Using initializeWebView sets the WaitForLoadedClient
-     * into the WebView. If a test needs to set a specific WebViewClient and
-     * needs the waitForLoadComplete capability then it should derive from
-     * WaitForLoadedClient or call WaitForLoadUrl.onPageFinished.
-     */
-    public static class WaitForLoadedClient extends WebViewClient {
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            super.onPageFinished(view, url);
-            WaitForLoadUrl.getInstance().onPageFinished();
-        }
-
-        @Override
-        public void onPageStarted(WebView view, String url, Bitmap favicon) {
-            super.onPageStarted(view, url, favicon);
-            WaitForLoadUrl.getInstance().onPageStarted();
-        }
-    }
-
-    /**
-     * A PictureListener that captures the onNewPicture for use in
-     * waitForLoadComplete. Using initializeWebView sets the PictureListener
-     * into the WebView. If a test needs to set a specific PictureListener and
-     * needs the waitForLoadComplete capability then it should call
-     * WaitForLoadUrl.onNewPicture.
-     */
-    private static class WaitForNewPicture implements PictureListener {
-        @Override
-        public void onNewPicture(WebView view, Picture picture) {
-            WaitForLoadUrl.getInstance().onNewPicture();
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/src/android/webkit/cts/WebViewOnUiThread.java b/tests/src/android/webkit/cts/WebViewOnUiThread.java
index 8b81463..c9dc914 100644
--- a/tests/src/android/webkit/cts/WebViewOnUiThread.java
+++ b/tests/src/android/webkit/cts/WebViewOnUiThread.java
@@ -16,43 +16,131 @@
 
 package android.webkit.cts;
 
+import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
+import android.graphics.Picture;
+import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
 import android.test.InstrumentationTestCase;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.webkit.DownloadListener;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
+import android.webkit.WebView.HitTestResult;
+import android.webkit.WebView.PictureListener;
 import android.webkit.WebViewClient;
 
 import junit.framework.Assert;
 
+import java.io.File;
+
 
 /**
  * Many tests need to run WebView code in the UI thread. This class
- * wraps a WebView so that calls are ensured to arrive on the UI Thread.
+ * wraps a WebView so that calls are ensured to arrive on the UI thread.
+ *
+ * All methods may be run on either the UI thread or test thread.
  */
 public class WebViewOnUiThread {
+    /**
+     * The maximum time, in milliseconds (10 seconds) to wait for a load
+     * to be triggered.
+     */
+    private static final long LOAD_TIMEOUT = 10000;
+
+    /**
+     * Set to true after onPageFinished is called.
+     */
+    private boolean mLoaded;
+
+    /**
+     * Set to true after onNewPicture is called. Reset when onPageStarted
+     * is called.
+     */
+    private boolean mNewPicture;
+
+    /**
+     * The progress, in percentage, of the page load. Valid values are between
+     * 0 and 100.
+     */
+    private int mProgress;
+
+    /**
+     * The test that this class is being used in. Used for runTestOnUiThread.
+     */
     private InstrumentationTestCase mTest;
+
+    /**
+     * The WebView that calls will be made on.
+     */
     private WebView mWebView;
 
     /**
      * Initializes the webView with a WebViewClient, WebChromeClient,
-     * and PictureListener as per WaitForLoadUrl.initializeWebView
-     * to prepare for loadUrl.
+     * and PictureListener to prepare for loadUrlAndWaitForCompletion.
      *
-     * This method should be called during setUp so as to reinitialize
-     * between calls.
+     * A new WebViewOnUiThread should be called during setUp so as to
+     * reinitialize between calls.
      *
      * @param test The test in which this is being run.
      * @param webView The webView that the methods should call.
-     * @see WaitForLoadUrl#initializeWebView
      * @see loadUrlAndWaitForCompletion
      */
     public WebViewOnUiThread(InstrumentationTestCase test, WebView webView) {
         mTest = test;
         mWebView = webView;
-        WaitForLoadUrl.getInstance().initializeWebView(mTest, mWebView);
+        final WebViewClient webViewClient = new WaitForLoadedClient(this);
+        final WebChromeClient webChromeClient = new WaitForProgressClient(this);
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.setWebViewClient(webViewClient);
+                mWebView.setWebChromeClient(webChromeClient);
+                mWebView.setPictureListener(new WaitForNewPicture());
+            }
+        });
+    }
+
+    /**
+     * Called from WaitForNewPicture, this is used to indicate that
+     * the page has been drawn.
+     */
+    synchronized public void onNewPicture() {
+        mNewPicture = true;
+        this.notifyAll();
+    }
+
+    /**
+     * Called from WaitForLoadedClient, this is used to clear the picture
+     * draw state so that draws before the URL begins loading don't count.
+     */
+    synchronized public void onPageStarted() {
+        mNewPicture = false; // Earlier paints won't count.
+    }
+
+    /**
+     * Called from WaitForLoadedClient, this is used to indicate that
+     * the page is loaded, but not drawn yet.
+     */
+    synchronized public void onPageFinished() {
+        mLoaded = true;
+        this.notifyAll();
+    }
+
+    /**
+     * Called from the WebChrome client, this sets the current progress
+     * for a page.
+     * @param progress The progress made so far between 0 and 100.
+     */
+    synchronized public void onProgressChanged(int progress) {
+        mProgress = progress;
+        this.notifyAll();
     }
 
     public void setWebViewClient(final WebViewClient webViewClient) {
@@ -73,6 +161,33 @@
         });
     }
 
+    public void setPictureListener(final PictureListener pictureListener) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.setPictureListener(pictureListener);
+            }
+        });
+    }
+
+    public void setDownloadListener(final DownloadListener listener) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.setDownloadListener(listener);
+            }
+        });
+    }
+
+    public void setBackgroundColor(final int color) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.setBackgroundColor(color);
+            }
+        });
+    }
+
     public void clearCache(final boolean includeDiskFiles) {
         runOnUiThread(new Runnable() {
             @Override
@@ -109,20 +224,92 @@
         });
     }
 
-    public void reload() {
+    public void removeJavascriptInterface(final String interfaceName) {
         runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mWebView.reload();
+                mWebView.removeJavascriptInterface(interfaceName);
             }
         });
     }
 
-    public void loadUrl(final String url) {
+    public void addJavascriptInterface(final Object object, final String name) {
         runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mWebView.loadUrl(url);
+                mWebView.addJavascriptInterface(object, name);
+            }
+        });
+    }
+
+    public void flingScroll(final int vx, final int vy) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.flingScroll(vx, vy);
+            }
+        });
+    }
+
+    public void requestFocusNodeHref(final Message hrefMsg) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.requestFocusNodeHref(hrefMsg);
+            }
+        });
+    }
+
+    public void requestImageRef(final Message msg) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.requestImageRef(msg);
+            }
+        });
+    }
+
+    public void setInitialScale(final int scaleInPercent) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.setInitialScale(scaleInPercent);
+            }
+        });
+    }
+
+    public void clearSslPreferences() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.clearSslPreferences();
+            }
+        });
+    }
+
+    public void resumeTimers() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.resumeTimers();
+            }
+        });
+    }
+
+    public void findNext(final boolean forward) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.findNext(forward);
+            }
+        });
+    }
+
+    public void clearMatches() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.clearMatches();
             }
         });
     }
@@ -134,125 +321,262 @@
      * @param url The URL to load.
      */
     public void loadUrlAndWaitForCompletion(final String url) {
-        runOnUiThread(new Runnable() {
+        callAndWait(new Runnable() {
             @Override
             public void run() {
                 mWebView.loadUrl(url);
             }
         });
-        WaitForLoadUrl.getInstance().waitForLoadComplete(mWebView);
     }
 
-    public String getTitle() {
-        class TitleGetter implements Runnable {
-            private String mTitle;
-
+    public void loadDataAndWaitForCompletion(final String data,
+            final String mimeType, final String encoding) {
+        callAndWait(new Runnable() {
             @Override
             public void run() {
-                mTitle = mWebView.getTitle();
+                mWebView.loadData(data, mimeType, encoding);
             }
-
-            public String getTitle() {
-                return mTitle;
-            }
-        }
-        TitleGetter titleGetter = new TitleGetter();
-        runOnUiThread(titleGetter);
-        return titleGetter.getTitle();
+        });
     }
 
-    public WebSettings getSettings() {
-        class SettingsGetter implements Runnable {
-            private WebSettings mWebSettings;
-
+    public void loadDataWithBaseURLAndWaitForCompletion(final String baseUrl,
+            final String data, final String mimeType, final String encoding,
+            final String historyUrl) {
+        callAndWait(new Runnable() {
             @Override
             public void run() {
-                mWebSettings = mWebView.getSettings();
+                mWebView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding,
+                        historyUrl);
             }
-
-            public WebSettings getSettings() {
-                return mWebSettings;
-            }
-        }
-
-        SettingsGetter settingsGetter = new SettingsGetter();
-        runOnUiThread(settingsGetter);
-        return settingsGetter.getSettings();
-    }
-
-    public WebBackForwardList copyBackForwardList() {
-        class BackForwardCopier implements Runnable {
-            private WebBackForwardList mBackForwardList;
-
-            @Override
-            public void run() {
-                mBackForwardList = mWebView.copyBackForwardList();
-            }
-
-            public WebBackForwardList getBackForwardList() {
-                return mBackForwardList;
-            }
-        }
-        BackForwardCopier backForwardCopier = new BackForwardCopier();
-        runOnUiThread(backForwardCopier);
-        return backForwardCopier.getBackForwardList();
+        });
     }
 
     /**
-     * @see android.webkit.WebView.WebView#
+     * Reloads a page and waits for it to complete reloading. Use reload
+     * if it is a form resubmission and the onFormResubmission responds
+     * by telling WebView not to resubmit it.
      */
-    public Bitmap getFavicon() {
-        class FaviconGetter implements Runnable {
-            private Bitmap mFavicon;
-
+    public void reloadAndWaitForCompletion() {
+        callAndWait(new Runnable() {
             @Override
             public void run() {
-                mFavicon = mWebView.getFavicon();
+                mWebView.reload();
             }
+        });
+    }
 
-            public Bitmap getFavicon() {
-                return mFavicon;
+    /**
+     * Reload the previous URL. Use reloadAndWaitForCompletion unless
+     * it is a form resubmission and the onFormResubmission responds
+     * by telling WebView not to resubmit it.
+     */
+    public void reload() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.reload();
             }
+        });
+    }
+
+    /**
+     * Use this only when JavaScript causes a page load to wait for the
+     * page load to complete. Otherwise use loadUrlAndWaitForCompletion or
+     * similar functions.
+     */
+    public void waitForLoadCompletion() {
+        if (isUiThread()) {
+            waitOnUiThread();
+        } else {
+            waitOnTestThread();
         }
-        FaviconGetter favIconGetter = new FaviconGetter();
-        runOnUiThread(favIconGetter);
-        return favIconGetter.getFavicon();
+        clearLoad();
+    }
+
+    public String getTitle() {
+        return getValue(new ValueGetter<String>() {
+            @Override
+            public String capture() {
+                return mWebView.getTitle();
+            }
+        });
+    }
+
+    public WebSettings getSettings() {
+        return getValue(new ValueGetter<WebSettings>() {
+            @Override
+            public WebSettings capture() {
+                return mWebView.getSettings();
+            }
+        });
+    }
+
+    public WebBackForwardList copyBackForwardList() {
+        return getValue(new ValueGetter<WebBackForwardList>() {
+            @Override
+            public WebBackForwardList capture() {
+                return mWebView.copyBackForwardList();
+            }
+        });
+    }
+
+    public Bitmap getFavicon() {
+        return getValue(new ValueGetter<Bitmap>() {
+            @Override
+            public Bitmap capture() {
+                return mWebView.getFavicon();
+            }
+        });
     }
 
     public String getUrl() {
-        class UrlGetter implements Runnable {
-            private String mUrl;
-
+        return getValue(new ValueGetter<String>() {
             @Override
-            public void run() {
-                mUrl = mWebView.getUrl();
+            public String capture() {
+                return mWebView.getUrl();
             }
-
-            public String getUrl() {
-                return mUrl;
-            }
-        }
-        UrlGetter urlGetter = new UrlGetter();
-        runOnUiThread(urlGetter);
-        return urlGetter.getUrl();
+        });
     }
 
     public int getProgress() {
-        class ProgressGetter implements Runnable {
-            private int mProgress;
-
+        return getValue(new ValueGetter<Integer>() {
             @Override
-            public void run() {
-                mProgress = mWebView.getProgress();
+            public Integer capture() {
+                return mWebView.getProgress();
             }
+        });
+    }
 
-            public int getProgress() {
-                return mProgress;
+    public int getHeight() {
+        return getValue(new ValueGetter<Integer>() {
+            @Override
+            public Integer capture() {
+                return mWebView.getHeight();
             }
-        }
-        ProgressGetter progressGetter = new ProgressGetter();
-        runOnUiThread(progressGetter);
-        return progressGetter.getProgress();
+        });
+    }
+
+    public int getContentHeight() {
+        return getValue(new ValueGetter<Integer>() {
+            @Override
+            public Integer capture() {
+                return mWebView.getContentHeight();
+            }
+        });
+    }
+
+    public boolean savePicture(final Bundle b, final File dest) {
+        return getValue(new ValueGetter<Boolean>() {
+            @Override
+            public Boolean capture() {
+                return mWebView.savePicture(b, dest);
+            }
+        });
+    }
+
+    public boolean pageUp(final boolean top) {
+        return getValue(new ValueGetter<Boolean>() {
+            @Override
+            public Boolean capture() {
+                return mWebView.pageUp(top);
+            }
+        });
+    }
+
+    public boolean pageDown(final boolean bottom) {
+        return getValue(new ValueGetter<Boolean>() {
+            @Override
+            public Boolean capture() {
+                return mWebView.pageDown(bottom);
+            }
+        });
+    }
+
+    public int[] getLocationOnScreen() {
+        final int[] location = new int[2];
+        return getValue(new ValueGetter<int[]>() {
+            @Override
+            public int[] capture() {
+                mWebView.getLocationOnScreen(location);
+                return location;
+            }
+        });
+    }
+
+    public float getScale() {
+        return getValue(new ValueGetter<Float>() {
+            @Override
+            public Float capture() {
+                return mWebView.getScale();
+            }
+        });
+    }
+
+    public boolean requestFocus(final int direction,
+            final Rect previouslyFocusedRect) {
+        return getValue(new ValueGetter<Boolean>() {
+            @Override
+            public Boolean capture() {
+                return mWebView.requestFocus(direction, previouslyFocusedRect);
+            }
+        });
+    }
+
+    public HitTestResult getHitTestResult() {
+        return getValue(new ValueGetter<HitTestResult>() {
+            @Override
+            public HitTestResult capture() {
+                return mWebView.getHitTestResult();
+            }
+        });
+    }
+
+    public int getScrollX() {
+        return getValue(new ValueGetter<Integer>() {
+            @Override
+            public Integer capture() {
+                return mWebView.getScrollX();
+            }
+        });
+    }
+
+    public int getScrollY() {
+        return getValue(new ValueGetter<Integer>() {
+            @Override
+            public Integer capture() {
+                return mWebView.getScrollY();
+            }
+        });
+    }
+
+    public final DisplayMetrics getDisplayMetrics() {
+        return getValue(new ValueGetter<DisplayMetrics>() {
+            @Override
+            public DisplayMetrics capture() {
+                return mWebView.getContext().getResources().getDisplayMetrics();
+            }
+        });
+    }
+
+    public boolean requestChildRectangleOnScreen(final View child,
+            final Rect rect,
+            final boolean immediate) {
+        return getValue(new ValueGetter<Boolean>() {
+            @Override
+            public Boolean capture() {
+                return mWebView.requestChildRectangleOnScreen(child, rect,
+                        immediate);
+            }
+        });
+    }
+
+    public int findAll(final String find) {
+        return getValue(new ValueGetter<Integer>() {
+            @Override
+            public Integer capture() {
+                return mWebView.findAll(find);
+            }
+        });
     }
 
     /**
@@ -271,7 +595,8 @@
                 mTest.runTestOnUiThread(r);
             }
         } catch (Throwable t) {
-            Assert.fail("Unexpected error while running on UI thread.");
+            Assert.fail("Unexpected error while running on UI thread: "
+                    + t.getMessage());
         }
     }
 
@@ -283,6 +608,26 @@
         return mWebView;
     }
 
+    private <T> T getValue(ValueGetter<T> getter) {
+        runOnUiThread(getter);
+        return getter.getValue();
+    }
+
+    private abstract class ValueGetter<T> implements Runnable {
+        private T mValue;
+
+        @Override
+        public void run() {
+            mValue = capture();
+        }
+
+        protected abstract T capture();
+
+        public T getValue() {
+           return mValue;
+        }
+    }
+
     /**
      * Returns true if the current thread is the UI thread based on the
      * Looper.
@@ -290,4 +635,150 @@
     private static boolean isUiThread() {
         return (Looper.myLooper() == Looper.getMainLooper());
     }
+
+    /**
+     * @return Whether or not the load has finished.
+     */
+    private synchronized boolean isLoaded() {
+        return mLoaded && mNewPicture && mProgress == 100;
+    }
+
+    /**
+     * Makes a WebView call, waits for completion and then resets the
+     * load state in preparation for the next load call.
+     * @param call The call to make on the UI thread prior to waiting.
+     */
+    private void callAndWait(Runnable call) {
+        Assert.assertTrue("WebViewOnUiThread.load*AndWaitForCompletion calls "
+                + "may not be mixed with load* calls directly on WebView "
+                + "without calling waitForLoadCompletion after the load",
+                !mLoaded);
+        runOnUiThread(call);
+        waitForLoadCompletion();
+    }
+
+    /**
+     * Called whenever a load has been completed so that a subsequent call to
+     * waitForLoadCompletion doesn't return immediately.
+     */
+    synchronized private void clearLoad() {
+        mLoaded = false;
+        mNewPicture = false;
+        mProgress = 0;
+    }
+
+    /**
+     * Uses a polling mechanism, while pumping messages to check when the
+     * load completes.
+     */
+    private void waitOnUiThread() {
+        new PollingCheck(LOAD_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                pumpMessages();
+                return isLoaded();
+            }
+        }.run();
+    }
+
+    /**
+     * Uses a wait/notify to check when the load completes.
+     */
+    private synchronized void waitOnTestThread() {
+        try {
+            long waitEnd = SystemClock.uptimeMillis() + LOAD_TIMEOUT;
+            long timeRemaining = LOAD_TIMEOUT;
+            while (!isLoaded() && timeRemaining > 0) {
+                this.wait(timeRemaining);
+                timeRemaining = waitEnd - SystemClock.uptimeMillis();
+            }
+        } catch (InterruptedException e) {
+            // We'll just drop out of the loop and fail
+        }
+        Assert.assertTrue("Load failed to complete before timeout", isLoaded());
+    }
+
+    /**
+     * Pumps all currently-queued messages in the UI thread and then exits.
+     * This is useful to force processing while running tests in the UI thread.
+     */
+    private void pumpMessages() {
+        class ExitLoopException extends RuntimeException {
+        }
+
+        // Force loop to exit when processing this. Loop.quit() doesn't
+        // work because this is the main Loop.
+        mWebView.getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                throw new ExitLoopException(); // exit loop!
+            }
+        });
+        try {
+            // Pump messages until our message gets through.
+            Looper.loop();
+        } catch (ExitLoopException e) {
+        }
+    }
+
+    /**
+     * A WebChromeClient used to capture the onProgressChanged for use
+     * in waitFor functions. If a test must override the WebChromeClient,
+     * it can derive from this class or call onProgressChanged
+     * directly.
+     */
+    public static class WaitForProgressClient extends WebChromeClient {
+        private WebViewOnUiThread mOnUiThread;
+
+        public WaitForProgressClient(WebViewOnUiThread onUiThread) {
+            mOnUiThread = onUiThread;
+        }
+
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            super.onProgressChanged(view, newProgress);
+            mOnUiThread.onProgressChanged(newProgress);
+        }
+    }
+
+    /**
+     * A WebViewClient that captures the onPageFinished for use in
+     * waitFor functions. Using initializeWebView sets the WaitForLoadedClient
+     * into the WebView. If a test needs to set a specific WebViewClient and
+     * needs the waitForCompletion capability then it should derive from
+     * WaitForLoadedClient or call WebViewOnUiThread.onPageFinished.
+     */
+    public static class WaitForLoadedClient extends WebViewClient {
+        private WebViewOnUiThread mOnUiThread;
+
+        public WaitForLoadedClient(WebViewOnUiThread onUiThread) {
+            mOnUiThread = onUiThread;
+        }
+
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+            mOnUiThread.onPageFinished();
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            mOnUiThread.onPageStarted();
+        }
+    }
+
+    /**
+     * A PictureListener that captures the onNewPicture for use in
+     * waitForLoadCompletion. Using initializeWebView sets the PictureListener
+     * into the WebView. If a test needs to set a specific PictureListener and
+     * needs the waitForCompletion capability then it should call
+     * WebViewOnUiThread.onNewPicture.
+     */
+    private class WaitForNewPicture implements PictureListener {
+        @Override
+        public void onNewPicture(WebView view, Picture picture) {
+            WebViewOnUiThread.this.onNewPicture();
+        }
+    }
 }
diff --git a/tests/tests/acceleration/Android.mk b/tests/tests/acceleration/Android.mk
index 3e2acac..93c4d51 100644
--- a/tests/tests/acceleration/Android.mk
+++ b/tests/tests/acceleration/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/accessibilityservice/Android.mk b/tests/tests/accessibilityservice/Android.mk
index 71b7537..4cac305 100644
--- a/tests/tests/accessibilityservice/Android.mk
+++ b/tests/tests/accessibilityservice/Android.mk
@@ -34,4 +34,4 @@
 
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/accounts/Android.mk b/tests/tests/accounts/Android.mk
index d9e142b..2806bbe 100644
--- a/tests/tests/accounts/Android.mk
+++ b/tests/tests/accounts/Android.mk
@@ -29,5 +29,4 @@
 
 LOCAL_PACKAGE_NAME := CtsAccountManagerTestCases
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/admin/Android.mk b/tests/tests/admin/Android.mk
index 3228d85..8c71e0c 100644
--- a/tests/tests/admin/Android.mk
+++ b/tests/tests/admin/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/animation/Android.mk b/tests/tests/animation/Android.mk
index ed9874e..95cc614 100644
--- a/tests/tests/animation/Android.mk
+++ b/tests/tests/animation/Android.mk
@@ -30,5 +30,5 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_SDK_VERSION := current
-include $(BUILD_PACKAGE)
 
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index a9b75df..b3aae14 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -29,4 +29,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/bluetooth/Android.mk b/tests/tests/bluetooth/Android.mk
index d1bb4ec..94c6c19 100644
--- a/tests/tests/bluetooth/Android.mk
+++ b/tests/tests/bluetooth/Android.mk
@@ -32,4 +32,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index a2f0e0f..ae2aee8 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -29,5 +29,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/database/Android.mk b/tests/tests/database/Android.mk
index b565854..85cbe1b 100644
--- a/tests/tests/database/Android.mk
+++ b/tests/tests/database/Android.mk
@@ -31,5 +31,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/dpi/Android.mk b/tests/tests/dpi/Android.mk
index ffbe8a3..2f256c4 100644
--- a/tests/tests/dpi/Android.mk
+++ b/tests/tests/dpi/Android.mk
@@ -30,7 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
 
 # ============================================================
 
diff --git a/tests/tests/dpi/AndroidManifest.xml b/tests/tests/dpi/AndroidManifest.xml
index 562579a..6e141ac 100644
--- a/tests/tests/dpi/AndroidManifest.xml
+++ b/tests/tests/dpi/AndroidManifest.xml
@@ -21,7 +21,7 @@
     <application>
         <uses-library android:name="android.test.runner" />
 
-        <activity android:name="android.dpi.cts.ConfigurationScreenLayoutActivity"
+        <activity android:name="android.dpi.cts.OrientationActivity"
                 android:configChanges="orientation" />
     </application>
 
diff --git a/tests/tests/dpi/src/android/dpi/cts/AspectRatioTest.java b/tests/tests/dpi/src/android/dpi/cts/AspectRatioTest.java
new file mode 100644
index 0000000..74a9f22
--- /dev/null
+++ b/tests/tests/dpi/src/android/dpi/cts/AspectRatioTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.dpi.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AspectRatioTest extends ActivityInstrumentationTestCase2<OrientationActivity> {
+
+    private static final int[] ORIENTATIONS = new int[] {
+        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
+        ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
+    };
+
+    public AspectRatioTest() {
+        super(OrientationActivity.class);
+    }
+
+    /**
+     * Get all the aspect rations in different orientations. They could be
+     * different due to the system bar being different sizes. Test that
+     * one of the aspect ratios is within the range.
+     */
+    public void testAspectRatio() throws Exception {
+        List<Double> aspectRatios = getAllAspectRatios();
+        for (double aspectRatio : aspectRatios) {
+            if (aspectRatio >= 1.333 && aspectRatio <= 1.86) {
+                return;
+            }
+        }
+        fail("Aspect ratios were not between 1.333 and 1.86: " + aspectRatios);
+    }
+
+    private List<Double> getAllAspectRatios() throws Exception {
+        List<Double> aspectRatios = new ArrayList<Double>();
+        for (int i = 0; i < ORIENTATIONS.length; i++) {
+            Activity activity = startOrientationActivity(ORIENTATIONS[i]);
+            aspectRatios.add(getAspectRatio(activity));
+            tearDown();
+        }
+        return aspectRatios;
+    }
+
+    private double getAspectRatio(Context context) {
+        WindowManager windowManager =
+                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display display = windowManager.getDefaultDisplay();
+        DisplayMetrics metrics = new DisplayMetrics();
+        display.getMetrics(metrics);
+
+        int max = Math.max(metrics.widthPixels, metrics.heightPixels);
+        int min = Math.min(metrics.widthPixels, metrics.heightPixels);
+        return (double) max / min;
+    }
+
+    private Activity startOrientationActivity(int orientation) {
+        Intent intent = new Intent();
+        intent.putExtra(OrientationActivity.EXTRA_ORIENTATION, orientation);
+        setActivityIntent(intent);
+        return getActivity();
+    }
+}
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
index 9fce9f1..d4c3611 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
@@ -27,7 +27,7 @@
 import android.view.WindowManager;
 
 public class ConfigurationScreenLayoutTest
-        extends ActivityInstrumentationTestCase2<ConfigurationScreenLayoutActivity> {
+        extends ActivityInstrumentationTestCase2<OrientationActivity> {
 
     private static final int[] ORIENTATIONS = new int[] {
             ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
@@ -37,7 +37,7 @@
     };
 
     public ConfigurationScreenLayoutTest() {
-        super(ConfigurationScreenLayoutActivity.class);
+        super(OrientationActivity.class);
     }
 
     public void testScreenLayout() throws Exception {
@@ -82,7 +82,7 @@
 
     private Activity startOrientationActivity(int orientation) {
         Intent intent = new Intent();
-        intent.putExtra(ConfigurationScreenLayoutActivity.EXTRA_ORIENTATION, orientation);
+        intent.putExtra(OrientationActivity.EXTRA_ORIENTATION, orientation);
         setActivityIntent(intent);
         return getActivity();
     }
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
index df254d2..937d8f8 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
@@ -46,12 +46,6 @@
         double density = 160.0d * metrics.density;
         assertTrue("Screen density must be at least 100 dpi: " + density, density >= 100.0d);
 
-        int max = Math.max(metrics.widthPixels, metrics.heightPixels);
-        int min = Math.min(metrics.widthPixels, metrics.heightPixels);
-        double aspectRatio = (double) max / min;
-        assertTrue("Aspect ratio must be between 1.333 and 1.86. It was " + aspectRatio,
-                aspectRatio >= 1.333 && aspectRatio <= 1.86);
-
         Set<Integer> allowedDensities = new HashSet<Integer>();
         allowedDensities.add(DisplayMetrics.DENSITY_LOW);
         allowedDensities.add(DisplayMetrics.DENSITY_MEDIUM);
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutActivity.java b/tests/tests/dpi/src/android/dpi/cts/OrientationActivity.java
similarity index 94%
rename from tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutActivity.java
rename to tests/tests/dpi/src/android/dpi/cts/OrientationActivity.java
index d4d268d..3bd76b6 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutActivity.java
+++ b/tests/tests/dpi/src/android/dpi/cts/OrientationActivity.java
@@ -22,7 +22,7 @@
 import android.view.WindowManager;
 
 /** {@link Activity} that calls {@link #setRequestedOrientation(int)} with the extra value. */
-public class ConfigurationScreenLayoutActivity extends Activity {
+public class OrientationActivity extends Activity {
 
     static final String EXTRA_ORIENTATION = "orientation";
 
diff --git a/tests/tests/dpi2/Android.mk b/tests/tests/dpi2/Android.mk
index 9dadcf9..cc11256 100644
--- a/tests/tests/dpi2/Android.mk
+++ b/tests/tests/dpi2/Android.mk
@@ -33,4 +33,4 @@
 # doesn't currently support setting LOCAL_SDK_VERSION to anything but
 # current.
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/drm/Android.mk b/tests/tests/drm/Android.mk
index 61e1f10..6e6ba56 100644
--- a/tests/tests/drm/Android.mk
+++ b/tests/tests/drm/Android.mk
@@ -32,4 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/effect/Android.mk b/tests/tests/effect/Android.mk
index 990a86a..075dc82 100644
--- a/tests/tests/effect/Android.mk
+++ b/tests/tests/effect/Android.mk
@@ -31,4 +31,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/example/Android.mk b/tests/tests/example/Android.mk
index d32f59b..7e2d841 100644
--- a/tests/tests/example/Android.mk
+++ b/tests/tests/example/Android.mk
@@ -32,4 +32,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/gesture/Android.mk b/tests/tests/gesture/Android.mk
index 22aeaec..f4fa8b3 100755
--- a/tests/tests/gesture/Android.mk
+++ b/tests/tests/gesture/Android.mk
@@ -29,5 +29,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/graphics/Android.mk b/tests/tests/graphics/Android.mk
index d0ebd37..9575dd3 100644
--- a/tests/tests/graphics/Android.mk
+++ b/tests/tests/graphics/Android.mk
@@ -32,5 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index 42c5f58..169fb56 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -1247,6 +1247,18 @@
         assertMeasureText(text, textChars, textSpan, 4, 7, widths[4] + widths[5] + widths[6]);
     }
 
+    public void testMeasureTextWithLongText() {
+        final int MAX_COUNT = 65535;
+        char[] longText = new char[MAX_COUNT];
+        for (int n = 0; n < MAX_COUNT; n++) {
+            longText[n] = 'm';
+        }
+
+        Paint p = new Paint();
+        float width = p.measureText(longText, 0, 1);
+        assertEquals(true, width > 0);
+    }
+
     /** Tests that all four overloads of measureText are the same and match some value. */
     private void assertMeasureText(String text, char[] textChars, SpannedString textSpan,
             int start, int end, float expectedWidth) {
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index dd3b72f..dd769fa 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -29,5 +29,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/holo/Android.mk b/tests/tests/holo/Android.mk
index 22afc85..513fb20 100644
--- a/tests/tests/holo/Android.mk
+++ b/tests/tests/holo/Android.mk
@@ -32,4 +32,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_dialog_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_dialog_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_dialog_minwidth_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_inputmethod_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_inputmethod_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_inputmethod_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_inputmethod_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_darkactionbar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_darkactionbar_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_darkactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_darkactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_minwidth_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_fullscreen_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_light_panel_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_light_panel_calendar_view.png
index 99d23a7..74819ce 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_light_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_light_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_fullscreen_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_panel_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_panel_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_notitlebar_calendar_view.png b/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_notitlebar_calendar_view.png
index bf1aaa5..355b200 100644
--- a/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_notitlebar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-hdpi/holo_wallpaper_notitlebar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_dialog_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_dialog_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_dialog_minwidth_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_minwidth_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_inputmethod_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_inputmethod_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_inputmethod_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_inputmethod_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_darkactionbar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_darkactionbar_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_darkactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_darkactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_minwidth_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_fullscreen_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_light_panel_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_light_panel_calendar_view.png
index 16deb8f..65d5ecb 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_light_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_light_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_fullscreen_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_panel_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_panel_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_notitlebar_calendar_view.png b/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_notitlebar_calendar_view.png
index 884bfc0..15c14ed 100644
--- a/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_notitlebar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-ldpi/holo_wallpaper_notitlebar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_dialog_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_dialog_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_dialog_minwidth_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_inputmethod_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_inputmethod_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_inputmethod_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_inputmethod_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_darkactionbar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_darkactionbar_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_darkactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_darkactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_minwidth_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_fullscreen_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_light_panel_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_light_panel_calendar_view.png
index 3b86863..551bd2e 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_light_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_light_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_fullscreen_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_panel_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_panel_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_notitlebar_calendar_view.png b/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_notitlebar_calendar_view.png
index 50d00ab..89c37c5 100644
--- a/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_notitlebar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-mdpi/holo_wallpaper_notitlebar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_minwidth_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_inputmethod_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_inputmethod_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_inputmethod_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_inputmethod_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_darkactionbar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_darkactionbar_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_darkactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_darkactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_minwidth_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_fullscreen_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_light_panel_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_light_panel_calendar_view.png
index 4d4616b..f02a0f6 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_light_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_light_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_fullscreen_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_panel_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_panel_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_notitlebar_calendar_view.png b/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_notitlebar_calendar_view.png
index 9029d16..b3fc31e 100644
--- a/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_notitlebar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-tvdpi/holo_wallpaper_notitlebar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_minwidth_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_inputmethod_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_inputmethod_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_inputmethod_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_inputmethod_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_darkactionbar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_darkactionbar_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_darkactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_darkactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_minwidth_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialog_noactionbar_minwidth_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_dialogwhenlarge_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_fullscreen_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_light_panel_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_light_panel_calendar_view.png
index 0e2ee26..c076d50 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_light_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_light_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_fullscreen_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_fullscreen_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_fullscreen_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_noactionbar_fullscreen_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_panel_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_panel_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_panel_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_panel_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_calendar_view.png
Binary files differ
diff --git a/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_notitlebar_calendar_view.png b/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_notitlebar_calendar_view.png
index 7fb7333..21585b3 100644
--- a/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_notitlebar_calendar_view.png
+++ b/tests/tests/holo/res/drawable-xhdpi/holo_wallpaper_notitlebar_calendar_view.png
Binary files differ
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index 0f9f88b..c8c92fd 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -34,7 +34,7 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
 
 # Include the associated library's makefile.
-include $(LOCAL_PATH)/libjnitest/Android.mk
\ No newline at end of file
+include $(LOCAL_PATH)/libjnitest/Android.mk
diff --git a/tests/tests/jni/libjnitest/helper.c b/tests/tests/jni/libjnitest/helper.c
index f974a59..831d5b5 100644
--- a/tests/tests/jni/libjnitest/helper.c
+++ b/tests/tests/jni/libjnitest/helper.c
@@ -58,7 +58,7 @@
 
         JniTestFunction *function = va_arg(args, JniTestFunction *);
 
-        LOGI("running %s", name);
+        ALOGI("running %s", name);
 
         char *oneResult = function(env);
         if (oneResult != NULL) {
diff --git a/tests/tests/jni/libjnitest/register.c b/tests/tests/jni/libjnitest/register.c
index d68b536..66eb265 100644
--- a/tests/tests/jni/libjnitest/register.c
+++ b/tests/tests/jni/libjnitest/register.c
@@ -32,25 +32,25 @@
 
     extern int register_InstanceNonce(JNIEnv *);
     if (register_InstanceNonce(env)) {
-        LOGE("failed to register InstanceNonce");
+        ALOGE("failed to register InstanceNonce");
         return JNI_ERR;
     }
 
     extern int register_StaticNonce(JNIEnv *);
     if (register_StaticNonce(env)) {
-        LOGE("failed to register StaticNonce");
+        ALOGE("failed to register StaticNonce");
         return JNI_ERR;
     }
 
     extern int register_JniCTest(JNIEnv *);
     if (register_JniCTest(env)) {
-        LOGE("failed to register JniCTest");
+        ALOGE("failed to register JniCTest");
         return JNI_ERR;
     }
 
     extern int register_JniCppTest(JNIEnv *);
     if (register_JniCppTest(env)) {
-        LOGE("failed to register JniCppTest");
+        ALOGE("failed to register JniCppTest");
         return JNI_ERR;
     }
 
diff --git a/tests/tests/location/Android.mk b/tests/tests/location/Android.mk
index d63d911..b53aaa0 100644
--- a/tests/tests/location/Android.mk
+++ b/tests/tests/location/Android.mk
@@ -32,5 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index df1de12..1a14f83 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -32,5 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/ndef/Android.mk b/tests/tests/ndef/Android.mk
index 4cb0b78..13e5624 100644
--- a/tests/tests/ndef/Android.mk
+++ b/tests/tests/ndef/Android.mk
@@ -31,4 +31,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index 1fd9ba0..1f1e387 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -32,5 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/openglperf/Android.mk b/tests/tests/openglperf/Android.mk
index 0663c73..571bbd7 100644
--- a/tests/tests/openglperf/Android.mk
+++ b/tests/tests/openglperf/Android.mk
@@ -27,8 +27,6 @@
 
 LOCAL_PACKAGE_NAME := CtsOpenGlPerfTestCases
 
-# uncomment when dalvik.annotation.Test* are removed or part of SDK
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index 35cafb9..54ebc4a 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -32,4 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index c1f7f4d..5d251de 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -30,6 +30,6 @@
 # uncomment when dalvik test annotations are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 96c6171..bdb4776 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -192,6 +192,8 @@
     private static final Set<String> OTHER_RANDOM_DIRECTORIES = new HashSet<String>(
             Arrays.asList(
                     "/app-cache/ciq/socket",
+                    "/cache/fotapkg",
+                    "/cache/fotapkg/tmp",
                     "/data/anr",
                     "/data/app",
                     "/data/app-private",
@@ -199,6 +201,7 @@
                     "/data/btips",
                     "/data/btips/TI",
                     "/data/btips/TI/opp",
+                    "/data/calibration",
                     "/data/dalvik-cache",
                     "/data/data",
                     "/data/data/.drm",
@@ -221,8 +224,12 @@
                     "/data/data/recovery",
                     "/data/dontpanic",
                     "/data/drm",
+                    "/data/drm/fwdlock",
+                    "/data/drm/IDM",
+                    "/data/drm/IDM/HTTP",
                     "/data/drm/rights",
                     "/data/dump",
+                    "/data/hwvefs",
                     "/data/htcfs",
                     "/data/local",
                     "/data/local/tmp",
@@ -234,10 +241,17 @@
                     "/data/misc/dhcp",
                     "/data/misc/wifi",
                     "/data/misc/wifi/sockets",
+                    "/data/misc/wpa_supplicant",
                     "/data/property",
+                    "/data/radio",
                     "/data/secure",
+                    "/data/sensors",
                     "/data/shared",
+                    "/data/simcom",
+                    "/data/simcom/btadd",
+                    "/data/simcom/simlog",
                     "/data/system",
+                    "/data/wapi",
                     "/data/wifi",
                     "/data/wiper",
                     "/data/wpstiles",
diff --git a/tests/tests/permission2/Android.mk b/tests/tests/permission2/Android.mk
index 9c62245..09fd104 100755
--- a/tests/tests/permission2/Android.mk
+++ b/tests/tests/permission2/Android.mk
@@ -27,5 +27,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/preference/Android.mk b/tests/tests/preference/Android.mk
index 886c166..7816c3b 100644
--- a/tests/tests/preference/Android.mk
+++ b/tests/tests/preference/Android.mk
@@ -30,4 +30,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index c33d98a..fba7cda 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -29,5 +29,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
index 717b468..7d78bd6 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
@@ -16,10 +16,6 @@
 
 package android.provider.cts;
 
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargetNew;
-
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.Cursor;
@@ -27,7 +23,6 @@
 import android.provider.MediaStore;
 import android.test.InstrumentationTestCase;
 
-@TestTargetClass(MediaStore.class)
 public class MediaStoreTest extends InstrumentationTestCase {
     private static final String TEST_VOLUME_NAME = "volume_for_cts";
 
@@ -62,11 +57,7 @@
         super.tearDown();
     }
 
-    @TestTargetNew(
-      level = TestLevel.COMPLETE,
-      method = "getMediaScannerUri",
-      args = {}
-    )
+
     public void testGetMediaScannerUri() {
         ContentValues values = new ContentValues();
         String selection = MediaStore.MEDIA_SCANNER_VOLUME + "=?";
@@ -93,4 +84,9 @@
         assertEquals(1, mContentResolver.delete(mScannerUri, null, null));
         assertNull(mContentResolver.query(mScannerUri, PROJECTION, null, null, null));
     }
+
+    public void testGetVersion() {
+        // Could be a version string or null...just check it doesn't blow up.
+        MediaStore.getVersion(getInstrumentation().getTargetContext());
+    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java
index 4e343cc..1138233 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java
@@ -16,20 +16,18 @@
 
 package android.provider.cts;
 
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargetNew;
-import dalvik.annotation.ToBeFixed;
-
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
 import android.provider.MediaStore.Audio.Genres;
+import android.provider.MediaStore.Audio.Media;
+import android.provider.MediaStore.Audio.Genres.Members;
+import android.provider.cts.MediaStoreAudioTestHelper.Audio1;
 import android.test.InstrumentationTestCase;
 
-@TestTargetClass(Genres.class)
 public class MediaStore_Audio_GenresTest extends InstrumentationTestCase {
     private ContentResolver mContentResolver;
 
@@ -40,14 +38,6 @@
         mContentResolver = getInstrumentation().getContext().getContentResolver();
     }
 
-    @TestTargetNew(
-      level = TestLevel.COMPLETE,
-      method = "getContentUri",
-      args = {String.class}
-    )
-    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
-            + "document related to the possible values of param volumeName. @throw clause "
-            + "should be added in to javadoc when getting uri for internal volume.")
     public void testGetContentUri() {
         assertNotNull(mContentResolver.query(
                 Genres.getContentUri(MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME), null, null,
@@ -103,4 +93,44 @@
         Uri uri = mContentResolver.insert(Genres.INTERNAL_CONTENT_URI, values);
         assertNull(uri);
     }
+
+    public void testGetContentUriForAudioId() {
+        // Insert an audio file into the content provider.
+        ContentValues values = Audio1.getInstance().getContentValues(true);
+        Uri audioUri = mContentResolver.insert(Media.EXTERNAL_CONTENT_URI, values);
+        long audioId = ContentUris.parseId(audioUri);
+        assertTrue(audioId != -1);
+
+        // Insert a genre into the content provider.
+        values.clear();
+        values.put(Genres.NAME, "Soda Pop");
+        Uri genreUri = mContentResolver.insert(Genres.EXTERNAL_CONTENT_URI, values);
+        long genreId = ContentUris.parseId(genreUri);
+        assertTrue(genreId != -1);
+
+        Cursor cursor = null;
+        try {
+            String volumeName = MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME;
+
+            // Check that the audio file has no genres yet.
+            Uri audioGenresUri = Genres.getContentUriForAudioId(volumeName, (int) audioId);
+            cursor = mContentResolver.query(audioGenresUri, null, null, null, null);
+            assertFalse(cursor.moveToNext());
+
+            // Link the audio file to the genre.
+            values.clear();
+            values.put(Members.AUDIO_ID, audioId);
+            Uri membersUri = Members.getContentUri(volumeName, genreId);
+            assertNotNull(mContentResolver.insert(membersUri, values));
+
+            // Check that the audio file has the genre it was linked to.
+            cursor = mContentResolver.query(audioGenresUri, null, null, null, null);
+            assertTrue(cursor.moveToNext());
+            assertEquals(genreId, cursor.getLong(cursor.getColumnIndex(Genres._ID)));
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
new file mode 100644
index 0000000..9432066
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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 android.provider.cts;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.provider.MediaStore.MediaColumns;
+import android.test.AndroidTestCase;
+
+public class MediaStore_FilesTest extends AndroidTestCase {
+
+    private ContentResolver mResolver;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResolver = mContext.getContentResolver();
+    }
+
+    public void testGetContentUri() {
+        String volumeName = MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME;
+        Uri allFilesUri = MediaStore.Files.getContentUri(volumeName);
+
+        // Get the current file count. We will check if this increases after
+        // adding a file to the provider.
+        int fileCount = getFileCount(allFilesUri);
+
+        // Check that inserting empty values causes an exception.
+        ContentValues values = new ContentValues();
+        try {
+            mResolver.insert(allFilesUri, values);
+            fail("Should throw an exception");
+        } catch (IllegalArgumentException e) {
+            // Expecting an exception
+        }
+
+        // Add a path for a file and check that the returned uri appends a
+        // path properly.
+        String dataPath = "does_not_really_exist.txt";
+        values.put(MediaColumns.DATA, dataPath);
+        Uri fileUri = mResolver.insert(allFilesUri, values);
+        long fileId = ContentUris.parseId(fileUri);
+        assertEquals(fileUri, ContentUris.withAppendedId(allFilesUri, fileId));
+
+        // Check that getContentUri with the file id produces the same url
+        Uri rowUri = MediaStore.Files.getContentUri(volumeName, fileId);
+        assertEquals(fileUri, rowUri);
+
+        // Check that the file count has increased.
+        int newFileCount = getFileCount(allFilesUri);
+        assertEquals(fileCount + 1, newFileCount);
+
+        // Check that the path we inserted was stored properly.
+        assertStringColumn(fileUri, MediaColumns.DATA, dataPath);
+
+        // Update the path and check that the database changed.
+        String updatedPath = "still_does_not_exist.txt";
+        values.put(MediaColumns.DATA, updatedPath);
+        assertEquals(1, mResolver.update(fileUri, values, null, null));
+        assertStringColumn(fileUri, MediaColumns.DATA, updatedPath);
+
+        // Delete the file and observe that the file count decreased.
+        assertEquals(1, mResolver.delete(fileUri, null, null));
+        assertEquals(fileCount, getFileCount(allFilesUri));
+
+        // Make sure the deleted file is not returned by the cursor.
+        Cursor cursor = mResolver.query(fileUri, null, null, null, null);
+        try {
+            assertFalse(cursor.moveToNext());
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private int getFileCount(Uri uri) {
+        Cursor cursor = mResolver.query(uri, null, null, null, null);
+        try {
+            return cursor.getCount();
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private void assertStringColumn(Uri fileUri, String columnName, String expectedValue) {
+        Cursor cursor = mResolver.query(fileUri, null, null, null, null);
+        try {
+            assertTrue(cursor.moveToNext());
+            int index = cursor.getColumnIndexOrThrow(columnName);
+            assertEquals(expectedValue, cursor.getString(index));
+        } finally {
+            cursor.close();
+        }
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java b/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
index 13ef4c8..a17bcdd 100644
--- a/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
@@ -16,11 +16,6 @@
 
 package android.provider.cts;
 
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargetNew;
-import dalvik.annotation.TestTargets;
-
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -30,7 +25,6 @@
 import android.provider.SearchRecentSuggestions;
 import android.test.ProviderTestCase2;
 
-@TestTargetClass(android.provider.SearchRecentSuggestions.class)
 public class SearchRecentSuggestionsTest extends
         ProviderTestCase2<TestSearchRecentSuggestionsProvider> {
     private final static String AUTHORITY_HEAD = "content://"
@@ -38,14 +32,14 @@
 
     private Uri mTestUri;
     private TestSearchRecentSuggestionsProvider mTestSRSProvider;
-    private Context mContext;
+    private Context mProviderContext;
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         mTestUri = Uri.parse(AUTHORITY_HEAD + "/suggestions");
         mTestSRSProvider = getProvider();
-        mContext = mTestSRSProvider.getContext();
+        mProviderContext = mTestSRSProvider.getContext();
     }
 
     public SearchRecentSuggestionsTest() {
@@ -53,40 +47,13 @@
                 TestSearchRecentSuggestionsProvider.AUTHORITY);
     }
 
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        method = "SearchRecentSuggestions",
-        args = {android.content.Context.class, java.lang.String.class, int.class}
-    )
     public void testConstructor() {
-        new SearchRecentSuggestions(mContext, TestSearchRecentSuggestionsProvider.AUTHORITY,
+        new SearchRecentSuggestions(mProviderContext, TestSearchRecentSuggestionsProvider.AUTHORITY,
                 TestSearchRecentSuggestionsProvider.MODE);
     }
 
-    @TestTargets({
-        @TestTargetNew(
-            level = TestLevel.COMPLETE,
-            method = "SearchRecentSuggestions",
-            args = {android.content.Context.class, java.lang.String.class, int.class}
-        ),
-        @TestTargetNew(
-            level = TestLevel.COMPLETE,
-            method = "saveRecentQuery",
-            args = {java.lang.String.class, java.lang.String.class}
-        ),
-        @TestTargetNew(
-            level = TestLevel.COMPLETE,
-            method = "clearHistory",
-            args = {}
-        ),
-        @TestTargetNew(
-            level = TestLevel.COMPLETE,
-            method = "truncateHistory",
-            args = {android.content.ContentResolver.class, int.class}
-        )
-    })
     public void testSearchRecentSuggestions() {
-        MySearchRecentSuggestions srs = new MySearchRecentSuggestions(mContext,
+        SearchRecentSuggestions srs = new MySearchRecentSuggestions(mProviderContext,
                 TestSearchRecentSuggestionsProvider.AUTHORITY,
                 TestSearchRecentSuggestionsProvider.MODE);
         Cursor c = mTestSRSProvider.query(mTestUri, null, null, null, null);
@@ -123,8 +90,8 @@
             waitForCursorCount(mTestUri, null, 3);
 
             // truncateHistory will delete the oldest one record
-            ContentResolver cr = mContext.getContentResolver();
-            srs.truncateHistory(cr, 2);
+            ContentResolver cr = mProviderContext.getContentResolver();
+            ((MySearchRecentSuggestions) srs).truncateHistory(cr, 2);
 
             waitForCursorCount(mTestUri, SearchRecentSuggestions.QUERIES_PROJECTION_2LINE, 2);
 
@@ -220,6 +187,7 @@
             super(context, authority, mode);
         }
 
+        @Override
         protected void truncateHistory(ContentResolver cr, int maxEntries) {
             super.truncateHistory(cr, maxEntries);
         }
@@ -228,6 +196,7 @@
     private void waitForCursorCount(final Uri uri, final String[] projection,
             final int expectedCount) {
         new PollingCheck() {
+            @Override
             protected boolean check() {
                 Cursor cursor = null;
                 try {
diff --git a/tests/tests/renderscript/Android.mk b/tests/tests/renderscript/Android.mk
index fc64614..d2137e2 100644
--- a/tests/tests/renderscript/Android.mk
+++ b/tests/tests/renderscript/Android.mk
@@ -34,4 +34,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/sax/Android.mk b/tests/tests/sax/Android.mk
index 749588a..9dc1847 100644
--- a/tests/tests/sax/Android.mk
+++ b/tests/tests/sax/Android.mk
@@ -29,4 +29,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 6ea5e1b..ef13886 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -28,4 +28,4 @@
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/speech/Android.mk b/tests/tests/speech/Android.mk
index 932c564..225acf3 100755
--- a/tests/tests/speech/Android.mk
+++ b/tests/tests/speech/Android.mk
@@ -31,5 +31,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telephony/Android.mk b/tests/tests/telephony/Android.mk
index 6ccc9b3..de5c2ac 100644
--- a/tests/tests/telephony/Android.mk
+++ b/tests/tests/telephony/Android.mk
@@ -33,5 +33,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 # #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/text/Android.mk b/tests/tests/text/Android.mk
index 5c44027..1ffeee9 100644
--- a/tests/tests/text/Android.mk
+++ b/tests/tests/text/Android.mk
@@ -32,5 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/util/Android.mk b/tests/tests/util/Android.mk
index cc65d12..d66e5e4 100644
--- a/tests/tests/util/Android.mk
+++ b/tests/tests/util/Android.mk
@@ -32,5 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index 037ae9a..4d82d91 100644
--- a/tests/tests/view/Android.mk
+++ b/tests/tests/view/Android.mk
@@ -29,5 +29,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/webkit/Android.mk b/tests/tests/webkit/Android.mk
index f739b42..1426dbb 100644
--- a/tests/tests/webkit/Android.mk
+++ b/tests/tests/webkit/Android.mk
@@ -32,5 +32,4 @@
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
index 6b4e93f..9a54ace 100644
--- a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
@@ -19,7 +19,7 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.HttpAuthHandler;
 import android.webkit.WebView;
-import android.webkit.cts.WaitForLoadUrl.WaitForLoadedClient;
+import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetClass;
@@ -126,7 +126,7 @@
                 CtsTestServer.getReasonString(HttpStatus.SC_UNAUTHORIZED), mOnUiThread.getTitle());
     }
 
-    private static class MyWebViewClient extends WaitForLoadedClient {
+    private class MyWebViewClient extends WaitForLoadedClient {
         String realm;
         boolean useHttpAuthUsernamePassword;
 
@@ -136,6 +136,7 @@
         private int mAuthCount;
 
         MyWebViewClient(boolean proceed, String user, String password) {
+            super(mOnUiThread);
             mProceed = proceed;
             mUser = user;
             mPassword = password;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index 0c66fac..c0a597b 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -25,7 +25,7 @@
 import android.webkit.WebIconDatabase;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
-import android.webkit.cts.WaitForLoadUrl.WaitForProgressClient;
+import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
 
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetClass;
@@ -77,7 +77,7 @@
         mOnUiThread.setWebChromeClient(webChromeClient);
 
         assertFalse(webChromeClient.hadOnProgressChanged());
-        mOnUiThread.loadUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        mOnUiThread.loadUrlAndWaitForCompletion(TestHtmlConstants.HELLO_WORLD_URL);
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -100,7 +100,7 @@
 
         assertFalse(webChromeClient.hadOnReceivedTitle());
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mOnUiThread.loadUrl(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -138,7 +138,7 @@
         assertFalse(webChromeClient.hadOnReceivedIcon());
 
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mOnUiThread.loadUrl(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -178,7 +178,8 @@
 
         // load a page that opens a child window, requests focus for the child and sets a timeout
         // after which the child will be closed
-        mOnUiThread.loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.JS_WINDOW_URL));
+        mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.
+                getAssetUrl(TestHtmlConstants.JS_WINDOW_URL));
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -243,7 +244,7 @@
         assertFalse(webChromeClient.hadOnJsAlert());
 
         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_ALERT_URL);
-        mOnUiThread.loadUrl(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -272,7 +273,7 @@
         assertFalse(webChromeClient.hadOnJsConfirm());
 
         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_CONFIRM_URL);
-        mOnUiThread.loadUrl(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -303,7 +304,7 @@
         final String promptResult = "CTS";
         webChromeClient.setPromptResult(promptResult);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_PROMPT_URL);
-        mOnUiThread.loadUrl(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -336,6 +337,10 @@
         private boolean mHadOnRequestFocus;
         private boolean mHadOnReceivedIcon;
 
+        public MockWebChromeClient() {
+            super(mOnUiThread);
+        }
+
         public void setPromptResult(String promptResult) {
             mPromptResult = promptResult;
         }
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 668a767..386b214 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -1014,11 +1014,46 @@
             args = {}
         )
     })
-    public void testSetAppCacheEnabled() throws Exception {
-        // Tests that when AppCache is enabled and used, but the database path
-        // is not set or is set to an inaccessible path, the WebView does not crash.
+    public void testAppCacheDisabled() throws Throwable {
+        // Test that when AppCache is disabled, we don't get any AppCache
+        // callbacks.
         startWebServer();
-        String url = mWebServer.getAppCacheUrl();
+        final String url = mWebServer.getAppCacheUrl();
+        mSettings.setJavaScriptEnabled(true);
+
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
+        new PollingCheck(WEBVIEW_TIMEOUT) {
+            protected boolean check() {
+                return "Loaded".equals(mOnUiThread.getTitle());
+            }
+        }.run();
+        // The page is now loaded. Wait for a further 1s to check no AppCache
+        // callbacks occur.
+        Thread.sleep(1000);
+        assertEquals("Loaded", mOnUiThread.getTitle());
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setAppCacheEnabled",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setAppCachePath",
+            args = {}
+        )
+    })
+    public void testAppCacheEnabled() throws Throwable {
+        // Note that the AppCache path can only be set once. This limits the
+        // amount of testing we can do, and means that we must test all aspects
+        // of setting the AppCache path in a single test to guarantee ordering.
+
+        // Test that when AppCache is enabled but no valid path is provided,
+        // we don't get any AppCache callbacks.
+        startWebServer();
+        final String url = mWebServer.getAppCacheUrl();
         mSettings.setAppCacheEnabled(true);
         mSettings.setJavaScriptEnabled(true);
 
@@ -1026,16 +1061,23 @@
         new PollingCheck(WEBVIEW_TIMEOUT) {
             @Override
             protected boolean check() {
-                return mOnUiThread.getTitle() != null && mOnUiThread.getTitle().equals("Done");
+                return "Loaded".equals(mOnUiThread.getTitle());
             }
         }.run();
+        // The page is now loaded. Wait for a further 1s to check no AppCache
+        // callbacks occur.
+        Thread.sleep(1000);
+        assertEquals("Loaded", mOnUiThread.getTitle());
 
-        mSettings.setAppCachePath("/data/foo");
+        // Test that when AppCache is enabled and a valid path is provided, we
+        // get an AppCache callback of some kind.
+        mSettings.setAppCachePath(getActivity().getDir("appcache", 0).getPath());
         mOnUiThread.loadUrlAndWaitForCompletion(url);
         new PollingCheck(WEBVIEW_TIMEOUT) {
             @Override
             protected boolean check() {
-                return mOnUiThread.getTitle() != null && mOnUiThread.getTitle().equals("Done");
+                return mOnUiThread.getTitle() != null
+                        && mOnUiThread.getTitle().endsWith("Callback");
             }
         }.run();
     }
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index c448aad..9d65200 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -25,7 +25,7 @@
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
-import android.webkit.cts.WaitForLoadUrl.WaitForLoadedClient;
+import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetClass;
@@ -95,7 +95,7 @@
         assertFalse(webViewClient.hasOnPageStartedCalled());
         assertFalse(webViewClient.hasOnLoadResourceCalled());
         assertFalse(webViewClient.hasOnPageFinishedCalled());
-        mOnUiThread.loadUrl(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
 
         new PollingCheck(TEST_TIMEOUT) {
             @Override
@@ -151,7 +151,8 @@
         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_FORM_URL);
         // this loads a form, which automatically posts itself
         mOnUiThread.loadUrlAndWaitForCompletion(url);
-        Thread.sleep(1000); // allow for javascript to post the form
+        // wait for JavaScript to post the form
+        mOnUiThread.waitForLoadCompletion();
         // the URL should have changed when the form was posted
         assertFalse(url.equals(mOnUiThread.getUrl()));
         // reloading the current URL should trigger the callback
@@ -264,6 +265,10 @@
         private boolean mOnUnhandledKeyEventCalled;
         private boolean mOnScaleChangedCalled;
 
+        public MockWebViewClient() {
+            super(mOnUiThread);
+        }
+
         public boolean hasOnPageStartedCalled() {
             return mOnPageStartedCalled;
         }
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index b95c448..f121f2a 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -38,7 +38,6 @@
 import android.test.UiThreadTest;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -55,8 +54,8 @@
 import android.webkit.WebView.PictureListener;
 import android.webkit.WebViewClient;
 import android.webkit.WebViewDatabase;
-import android.webkit.cts.WaitForLoadUrl.WaitForLoadedClient;
-import android.webkit.cts.WaitForLoadUrl.WaitForProgressClient;
+import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
+import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
 import android.widget.LinearLayout;
 
 import dalvik.annotation.TestLevel;
@@ -79,19 +78,13 @@
 
     private WebView mWebView;
     private CtsTestServer mWebServer;
-    private boolean mIsUiThreadDone;
+    private WebViewOnUiThread mOnUiThread;
 
     public WebViewTest() {
         super("com.android.cts.stub", WebViewStubActivity.class);
     }
 
     @Override
-    public void runTestOnUiThread(Runnable runnable) throws Throwable {
-        mIsUiThreadDone = false;
-        super.runTestOnUiThread(runnable);
-    }
-
-    @Override
     protected void setUp() throws Exception {
         super.setUp();
         mWebView = getActivity().getWebView();
@@ -99,22 +92,13 @@
         if (f.exists()) {
             f.delete();
         }
-        WaitForLoadUrl.getInstance().initializeWebView(this, mWebView);
+        mOnUiThread = new WebViewOnUiThread(this, mWebView);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        try {
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mWebView.clearHistory();
-                    mWebView.clearCache(true);
-                }
-            });
-        } catch(Throwable t) {
-            Log.w(LOGTAG, "tearDown(): Caught exception when posting Runnable to UI thread");
-        }
+        mOnUiThread.clearHistory();
+        mOnUiThread.clearCache(true);
         if (mWebServer != null) {
             mWebServer.shutdown();
         }
@@ -217,7 +201,7 @@
         assertTrue(settings.supportZoom());
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        assertLoadUrlSuccessfully(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         mWebView.invokeZoomPicker();
     }
 
@@ -406,8 +390,7 @@
 
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mWebView.loadUrl(url);
-        waitForLoadComplete();
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         assertEquals(100, mWebView.getProgress());
         assertEquals(url, mWebView.getUrl());
         assertEquals(url, mWebView.getOriginalUrl());
@@ -426,39 +409,25 @@
             args = {}
         )
     })
+    @UiThreadTest
     public void testGetOriginalUrl() throws Throwable {
         startWebServer(false);
         final String finalUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         final String redirectUrl =
                 mWebServer.getRedirectingAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertNull(mWebView.getUrl());
-                assertNull(mWebView.getOriginalUrl());
+        assertNull(mWebView.getUrl());
+        assertNull(mWebView.getOriginalUrl());
 
-                // By default, WebView sends an intent to ask the system to
-                // handle loading a new URL. We set a WebViewClient as
-                // WebViewClient.shouldOverrideUrlLoading() returns false, so
-                // the WebView will load the new URL.
-                mWebView.setWebViewClient(new WaitForLoadedClient());
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.loadUrl(redirectUrl);
-            }
-        });
+        // By default, WebView sends an intent to ask the system to
+        // handle loading a new URL. We set a WebViewClient as
+        // WebViewClient.shouldOverrideUrlLoading() returns false, so
+        // the WebView will load the new URL.
+        mOnUiThread.setWebViewClient(new WaitForLoadedClient(mOnUiThread));
+        mOnUiThread.loadUrlAndWaitForCompletion(redirectUrl);
 
-        // We need to yield the UI thread to allow the callback to
-        // WebViewClient.shouldOverrideUrlLoading() to be made.
-        waitForUiThreadDone();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(finalUrl, mWebView.getUrl());
-                assertEquals(redirectUrl, mWebView.getOriginalUrl());
-            }
-        });
+        assertEquals(finalUrl, mWebView.getUrl());
+        assertEquals(redirectUrl, mWebView.getOriginalUrl());
     }
 
     @TestTargetNew(
@@ -526,17 +495,17 @@
         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
 
-        assertLoadUrlSuccessfully(url1);
+        mOnUiThread.loadUrlAndWaitForCompletion(url1);
         pollingCheckWebBackForwardList(url1, 0, 1);
         assertGoBackOrForwardBySteps(false, -1);
         assertGoBackOrForwardBySteps(false, 1);
 
-        assertLoadUrlSuccessfully(url2);
+        mOnUiThread.loadUrlAndWaitForCompletion(url2);
         pollingCheckWebBackForwardList(url2, 1, 2);
         assertGoBackOrForwardBySteps(true, -1);
         assertGoBackOrForwardBySteps(false, 1);
 
-        assertLoadUrlSuccessfully(url3);
+        mOnUiThread.loadUrlAndWaitForCompletion(url3);
         pollingCheckWebBackForwardList(url3, 2, 3);
         assertGoBackOrForwardBySteps(true, -2);
         assertGoBackOrForwardBySteps(false, 1);
@@ -608,7 +577,7 @@
 
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.ADD_JAVA_SCRIPT_INTERFACE_URL);
-        assertLoadUrlSuccessfully(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         assertEquals("Original title", obj.waitForResult());
     }
 
@@ -625,27 +594,27 @@
                 "<body onload=\"document.title = typeof window.injectedObject;\"></body></html>";
 
         // Test that the property is initially undefined.
-        mWebView.loadData(setTitleToPropertyTypeHtml, "text/html", null);
-        waitForLoadComplete();
+        mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
+                "text/html", null);
         assertEquals("undefined", mWebView.getTitle());
 
         // Test that adding a null object has no effect.
         mWebView.addJavascriptInterface(null, "injectedObject");
-        mWebView.loadData(setTitleToPropertyTypeHtml, "text/html", null);
-        waitForLoadComplete();
+        mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
+                "text/html", null);
         assertEquals("undefined", mWebView.getTitle());
 
         // Test that adding an object gives an object type.
         final Object obj = new Object();
         mWebView.addJavascriptInterface(obj, "injectedObject");
-        mWebView.loadData(setTitleToPropertyTypeHtml, "text/html", null);
-        waitForLoadComplete();
+        mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
+                "text/html", null);
         assertEquals("object", mWebView.getTitle());
 
         // Test that trying to replace with a null object has no effect.
         mWebView.addJavascriptInterface(null, "injectedObject");
-        mWebView.loadData(setTitleToPropertyTypeHtml, "text/html", null);
-        waitForLoadComplete();
+        mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
+                "text/html", null);
         assertEquals("object", mWebView.getTitle());
     }
 
@@ -680,13 +649,13 @@
                     "</head><body onload=\"updateTitle();\"></body></html>";
 
             mWebView.addJavascriptInterface(obj, name);
-            mWebView.loadData(Uri.encode(setTitleToPropertyTypeHtml), "text/html", null);
-            waitForLoadComplete();
+            mOnUiThread.loadDataAndWaitForCompletion(
+                    Uri.encode(setTitleToPropertyTypeHtml), "text/html", null);
             assertEquals("object", mWebView.getTitle());
 
             mWebView.removeJavascriptInterface(name);
-            mWebView.loadData(Uri.encode(setTitleToPropertyTypeHtml), "text/html", null);
-            waitForLoadComplete();
+            mOnUiThread.loadDataAndWaitForCompletion(
+                    Uri.encode(setTitleToPropertyTypeHtml), "text/html", null);
             assertEquals("undefined", mWebView.getTitle());
         }
     }
@@ -705,14 +674,14 @@
 
         // Test that adding an object gives an object type.
         mWebView.addJavascriptInterface(new Object(), "injectedObject");
-        mWebView.loadData(setTitleToPropertyTypeHtml, "text/html", null);
-        waitForLoadComplete();
+        mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
+                "text/html", null);
         assertEquals("object", mWebView.getTitle());
 
         // Test that reloading the page after removing the object leaves the property undefined.
         mWebView.removeJavascriptInterface("injectedObject");
-        mWebView.loadData(setTitleToPropertyTypeHtml, "text/html", null);
-        waitForLoadComplete();
+        mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
+                "text/html", null);
         assertEquals("undefined", mWebView.getTitle());
     }
 
@@ -728,13 +697,8 @@
                 return "removedObject";
             }
             public void remove() throws Throwable {
-                runTestOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        mWebView.removeJavascriptInterface("removedObject");
-                        System.gc();
-                    }
-                });
+                mOnUiThread.removeJavascriptInterface("removedObject");
+                System.gc();
             }
         }
         class ResultObject {
@@ -759,18 +723,13 @@
 
         // Test that an object is still usable if removed while the page is in use, even if we have
         // no external references to it.
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.getSettings().setJavaScriptEnabled(true);
-                mWebView.addJavascriptInterface(new RemovedObject(), "removedObject");
-                mWebView.addJavascriptInterface(resultObject, "resultObject");
-                mWebView.loadData("<html><head></head>" +
-                        "<body onload=\"window.removedObject.remove();" +
-                        "resultObject.setResult(removedObject.toString());\"></body></html>",
-                        "text/html", null);
-            }
-        });
+        mOnUiThread.getSettings().setJavaScriptEnabled(true);
+        mOnUiThread.addJavascriptInterface(new RemovedObject(), "removedObject");
+        mOnUiThread.addJavascriptInterface(resultObject, "resultObject");
+        mOnUiThread.loadDataAndWaitForCompletion("<html><head></head>" +
+                "<body onload=\"window.removedObject.remove();" +
+                "resultObject.setResult(removedObject.toString());\"></body></html>",
+                "text/html", null);
         assertEquals("removedObject", resultObject.getResult());
     }
 
@@ -794,14 +753,8 @@
     public void testCapturePicture() throws Exception, Throwable {
         startWebServer(false);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // showing the blank page will make the picture filled with background color
-                mWebView.loadUrl(url);
-                waitForLoadComplete();
-            }
-        });
+        // showing the blank page will make the picture filled with background color
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         getInstrumentation().waitForIdleSync();
 
         class PictureRunnable implements Runnable {
@@ -816,8 +769,7 @@
                 assertBitmapFillWithColor(b, Color.WHITE);
 
                 mWebView.setBackgroundColor(Color.CYAN);
-                mWebView.reload();
-                waitForLoadComplete();
+                mOnUiThread.reloadAndWaitForCompletion();
             }
             public Picture getPicture() {
                 return mPicture;
@@ -860,7 +812,7 @@
             public void onNewPicture(WebView view, Picture picture) {
                 // Need to inform the listener tracking new picture
                 // for the "page loaded" knowledge since it has been replaced.
-                WaitForLoadUrl.getInstance().onNewPicture();
+                mOnUiThread.onNewPicture();
                 this.callCount += 1;
                 this.webView = view;
                 this.picture = picture;
@@ -870,13 +822,8 @@
         final MyPictureListener listener = new MyPictureListener();
         startWebServer(false);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setPictureListener(listener);
-                assertLoadUrlSuccessfully(url);
-            }
-        });
+        mOnUiThread.setPictureListener(listener);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
@@ -888,12 +835,7 @@
 
         final int oldCallCount = listener.callCount;
         final String newUrl = mWebServer.getAssetUrl(TestHtmlConstants.SMALL_IMG_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertLoadUrlSuccessfully(newUrl);
-            }
-        });
+        mOnUiThread.loadUrlAndWaitForCompletion(newUrl);
         new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
@@ -924,12 +866,7 @@
         mWebView.setBackgroundColor(Color.CYAN);
         startWebServer(false);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertLoadUrlSuccessfully(url);
-            }
-        });
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         getInstrumentation().waitForIdleSync();
 
         final Bundle bundle = new Bundle();
@@ -941,12 +878,7 @@
         try {
             assertTrue(bundle.isEmpty());
             assertEquals(0, f.length());
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    assertTrue(mWebView.savePicture(bundle, f));
-                }
-            });
+            assertTrue(mOnUiThread.savePicture(bundle, f));
 
             // File saving is done in a separate thread.
             new PollingCheck() {
@@ -963,14 +895,8 @@
             p.draw(new Canvas(b));
             assertBitmapFillWithColor(b, Color.CYAN);
 
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mWebView.setBackgroundColor(Color.WHITE);
-                    mWebView.reload();
-                    waitForLoadComplete();
-                }
-            });
+            mOnUiThread.setBackgroundColor(Color.WHITE);
+            mOnUiThread.reloadAndWaitForCompletion();
             getInstrumentation().waitForIdleSync();
 
             runTestOnUiThread(new Runnable() {
@@ -1115,22 +1041,23 @@
         )
     })
     public void testLoadData() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertNull(mWebView.getTitle());
-                mWebView.loadData("<html><head><title>Hello,World!</title></head><body></body>" +
-                        "</html>",
-                        "text/html", null);
-                waitForLoadComplete();
-                assertEquals("Hello,World!", mWebView.getTitle());
-            }
-        });
+        final String HTML_CONTENT =
+                "<html><head><title>Hello,World!</title></head><body></body>" +
+                "</html>";
+        assertNull(mOnUiThread.getTitle());
+        mOnUiThread.loadDataAndWaitForCompletion(HTML_CONTENT,
+                "text/html", null);
+        assertEquals("Hello,World!", mOnUiThread.getTitle());
 
         // Test that JavaScript can't access cross-origin content.
         class ConsoleMessageWebChromeClient extends WaitForProgressClient {
             private boolean mIsMessageLevelAvailable;
             private ConsoleMessage.MessageLevel mMessageLevel;
+
+            public ConsoleMessageWebChromeClient() {
+                super(mOnUiThread);
+            }
+
             @Override
             public synchronized boolean onConsoleMessage(ConsoleMessage message) {
                 mMessageLevel = message.messageLevel();
@@ -1155,8 +1082,9 @@
             @Override
             public void run() {
                 mWebView.getSettings().setJavaScriptEnabled(true);
-                mWebView.setWebChromeClient(webChromeClient);
-                mWebView.loadData("<html><head></head><body onload=\"" +
+                mOnUiThread.setWebChromeClient(webChromeClient);
+                mOnUiThread.loadDataAndWaitForCompletion(
+                        "<html><head></head><body onload=\"" +
                         "document.title = " +
                         "document.getElementById('frame').contentWindow.location.href;" +
                         "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
@@ -1193,38 +1121,36 @@
         startWebServer(false);
         String baseUrl = mWebServer.getAssetUrl("foo.html");
         String historyUrl = "random";
-        mWebView.loadDataWithBaseURL(baseUrl,
+        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
                 "<html><body><img src=\"" + imgUrl + "\"/></body></html>",
                 "text/html", "UTF-8", historyUrl);
-        waitForLoadComplete();
         assertTrue(mWebServer.getLastRequestUrl().endsWith(imgUrl));
         assertEquals(historyUrl, mWebView.getUrl());
 
         // Check that reported URL is "about:blank" when supplied history URL
         // is null.
         imgUrl = TestHtmlConstants.LARGE_IMG_URL;
-        mWebView.loadDataWithBaseURL(baseUrl,
+        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
                 "<html><body><img src=\"" + imgUrl + "\"/></body></html>",
                 "text/html", "UTF-8", null);
-        waitForLoadComplete();
         assertTrue(mWebServer.getLastRequestUrl().endsWith(imgUrl));
         assertEquals("about:blank", mWebView.getUrl());
 
         // Test that JavaScript can access content from the same origin as the base URL.
         mWebView.getSettings().setJavaScriptEnabled(true);
         final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mWebView.loadDataWithBaseURL(baseUrl, "<html><head></head><body onload=\"" +
+        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
+                "<html><head></head><body onload=\"" +
                 "document.title = document.getElementById('frame').contentWindow.location.href;" +
                 "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
                 "text/html", "UTF-8", null);
-        waitForLoadComplete();
         assertEquals(crossOriginUrl, mWebView.getTitle());
 
         // Check that when the base URL uses the 'data' scheme, a 'data' scheme URL is used and the
         // history URL is ignored.
-        mWebView.loadDataWithBaseURL("data:foo", "<html><body>bar</body></html>",
-                "text/html", "UTF-8", historyUrl);
-        waitForLoadComplete();
+        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("data:foo",
+                "<html><body>bar</body></html>", "text/html", "UTF-8",
+                historyUrl);
         assertTrue(mWebView.getUrl().indexOf("data:text/html,") == 0);
         assertTrue(mWebView.getUrl().indexOf("bar") > 0);
     }
@@ -1239,8 +1165,8 @@
     public void testFindAll() {
         String p = "<p>Find all instances of find on the page and highlight them.</p>";
 
-        mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", null);
-        waitForLoadComplete();
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "</body></html>", "text/html", null);
 
         assertEquals(2, mWebView.findAll("find"));
     }
@@ -1263,99 +1189,72 @@
         )
     })
     public void testFindNext() throws Throwable {
-        final ScrollRunnable runnable = new ScrollRunnable();
-
         final class StopScrollingPollingCheck extends PollingCheck {
             private int mPreviousScrollY = -1;
             @Override
             protected boolean check() {
                 getInstrumentation().waitForIdleSync();
-                try {
-                    runTestOnUiThread(runnable);
-                } catch (Throwable t) {}
+                int scrollY = mOnUiThread.getScrollY();
                 boolean hasStopped =
-                    (mPreviousScrollY == -1 ? false : (runnable.getScrollY() == mPreviousScrollY));
-                mPreviousScrollY = runnable.getScrollY();
+                    (mPreviousScrollY == -1 ? false : (scrollY == mPreviousScrollY));
+                mPreviousScrollY = scrollY;
                 return hasStopped;
             }
         }
 
-        final class FindNextRunnable implements Runnable {
-            private boolean mForward;
-            FindNextRunnable(boolean forward) {
-                mForward = forward;
-            }
-            @Override
-            public void run() {
-                mWebView.findNext(mForward);
-            }
-        }
+        // Reset the scaling so that finding the next "all" text will require scrolling.
+        mOnUiThread.setInitialScale(100);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Reset the scaling so that finding the next "all" text will require scrolling.
-                mWebView.setInitialScale(100);
+        DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
+        int dimension = Math.max(metrics.widthPixels, metrics.heightPixels);
+        // create a paragraph high enough to take up the entire screen
+        String p = "<p style=\"height:" + dimension + "px;\">" +
+                "Find all instances of a word on the page and highlight them.</p>";
 
-                DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
-                int dimension = Math.max(metrics.widthPixels, metrics.heightPixels);
-                // create a paragraph high enough to take up the entire screen
-                String p = "<p style=\"height:" + dimension + "px;\">" +
-                        "Find all instances of a word on the page and highlight them.</p>";
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p + p + "</body></html>", "text/html", null);
 
-                mWebView.loadData("<html><body>" + p + p + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-
-                // highlight all the strings found
-                mWebView.findAll("all");
-            }
-        });
+        // highlight all the strings found
+        mOnUiThread.findAll("all");
         getInstrumentation().waitForIdleSync();
 
-        runTestOnUiThread(runnable);
-        int previousScrollY = runnable.getScrollY();
+        int previousScrollY = mOnUiThread.getScrollY();
 
         // Focus "all" in the second page and assert that the view scrolls.
-        runTestOnUiThread(new FindNextRunnable(true));
+        mOnUiThread.findNext(true);
         new StopScrollingPollingCheck().run();
-        assertTrue(runnable.getScrollY() > previousScrollY);
-        previousScrollY = runnable.getScrollY();
+        assertTrue(mOnUiThread.getScrollY() > previousScrollY);
+        previousScrollY = mOnUiThread.getScrollY();
 
         // Focus "all" in the first page and assert that the view scrolls.
-        runTestOnUiThread(new FindNextRunnable(true));
+        mOnUiThread.findNext(true);
         new StopScrollingPollingCheck().run();
-        assertTrue(runnable.getScrollY() < previousScrollY);
-        previousScrollY = runnable.getScrollY();
+        assertTrue(mOnUiThread.getScrollY() < previousScrollY);
+        previousScrollY = mOnUiThread.getScrollY();
 
         // Focus "all" in the second page and assert that the view scrolls.
-        runTestOnUiThread(new FindNextRunnable(false));
+        mOnUiThread.findNext(false);
         new StopScrollingPollingCheck().run();
-        assertTrue(runnable.getScrollY() > previousScrollY);
-        previousScrollY = runnable.getScrollY();
+        assertTrue(mOnUiThread.getScrollY() > previousScrollY);
+        previousScrollY = mOnUiThread.getScrollY();
 
         // Focus "all" in the first page and assert that the view scrolls.
-        runTestOnUiThread(new FindNextRunnable(false));
+        mOnUiThread.findNext(false);
         new StopScrollingPollingCheck().run();
-        assertTrue(runnable.getScrollY() < previousScrollY);
-        previousScrollY = runnable.getScrollY();
+        assertTrue(mOnUiThread.getScrollY() < previousScrollY);
+        previousScrollY = mOnUiThread.getScrollY();
 
         // clear the result
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.clearMatches();
-            }
-        });
+        mOnUiThread.clearMatches();
         getInstrumentation().waitForIdleSync();
 
         // can not scroll any more
-        runTestOnUiThread(new FindNextRunnable(false));
+        mOnUiThread.findNext(false);
         new StopScrollingPollingCheck().run();
-        assertTrue(runnable.getScrollY() == previousScrollY);
+        assertTrue(mOnUiThread.getScrollY() == previousScrollY);
 
-        runTestOnUiThread(new FindNextRunnable(true));
+        mOnUiThread.findNext(true);
         new StopScrollingPollingCheck().run();
-        assertTrue(runnable.getScrollY() == previousScrollY);
+        assertTrue(mOnUiThread.getScrollY() == previousScrollY);
     }
 
     @TestTargetNew(
@@ -1395,9 +1294,8 @@
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mWebView.loadData("<html><body><img src=\"" + imgUrl + "\"/></body></html>",
-                        "text/html", null);
-                waitForLoadComplete();
+                mOnUiThread.loadDataAndWaitForCompletion("<html><body><img src=\""
+                        + imgUrl + "\"/></body></html>", "text/html", null);
                 Message response = new Message();
                 response.setTarget(handler);
                 assertFalse(handler.hasCalledHandleMessage());
@@ -1426,97 +1324,41 @@
         )
     })
     public void testPageScroll() throws Throwable {
-        final class PageUpRunnable implements Runnable {
-            private boolean mResult;
-            @Override
-            public void run() {
-                mResult = mWebView.pageUp(false);
-            }
-            public boolean getResult() {
-                return mResult;
-            }
-        }
-
-        final class PageDownRunnable implements Runnable {
-            private boolean mResult;
-            @Override
-            public void run() {
-                mResult = mWebView.pageDown(false);
-            }
-            public boolean getResult() {
-                return mResult;
-            }
-        }
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
-                int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
-                String p = "<p style=\"height:" + dimension + "px;\">" +
-                        "Scroll by half the size of the page.</p>";
-                mWebView.loadData("<html><body>" + p + p + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
+        int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
+        String p = "<p style=\"height:" + dimension + "px;\">" +
+                "Scroll by half the size of the page.</p>";
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + p + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(mWebView.pageDown(false));
-            }
-        });
+        assertTrue(mOnUiThread.pageDown(false));
 
-        PageDownRunnable pageDownRunnable = new PageDownRunnable();
         do {
             getInstrumentation().waitForIdleSync();
-            runTestOnUiThread(pageDownRunnable);
-        } while (pageDownRunnable.getResult());
+        } while (mOnUiThread.pageDown(false));
 
-        ScrollRunnable scrollRunnable = new ScrollRunnable();
         getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(scrollRunnable);
-        int bottomScrollY = scrollRunnable.getScrollY();
+        int bottomScrollY = mOnUiThread.getScrollY();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(mWebView.pageUp(false));
-            }
-        });
+        assertTrue(mOnUiThread.pageUp(false));
 
-        PageUpRunnable pageUpRunnable = new PageUpRunnable();
         do {
             getInstrumentation().waitForIdleSync();
-            runTestOnUiThread(pageUpRunnable);
-        } while (pageUpRunnable.getResult());
+        } while (mOnUiThread.pageUp(false));
 
         getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(scrollRunnable);
-        int topScrollY = scrollRunnable.getScrollY();
+        int topScrollY = mOnUiThread.getScrollY();
 
         // jump to the bottom
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(mWebView.pageDown(true));
-            }
-        });
+        assertTrue(mOnUiThread.pageDown(true));
         getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(scrollRunnable);
-        assertEquals(bottomScrollY, scrollRunnable.getScrollY());
+        assertEquals(bottomScrollY, mOnUiThread.getScrollY());
 
         // jump to the top
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(mWebView.pageUp(true));
-            }
-        });
+        assertTrue(mOnUiThread.pageUp(true));
         getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(scrollRunnable);
-        assertEquals(topScrollY, scrollRunnable.getScrollY());
+        assertEquals(topScrollY, mOnUiThread.getScrollY());
     }
 
     @TestTargetNew(
@@ -1525,60 +1367,27 @@
         args = {}
     )
     public void testGetContentHeight() throws Throwable {
-        final class HeightRunnable implements Runnable {
-            private int mHeight;
-            private int mContentHeight;
-            @Override
-            public void run() {
-                mHeight = mWebView.getHeight();
-                mContentHeight = mWebView.getContentHeight();
-            }
-            public int getHeight() {
-                return mHeight;
-            }
-            public int getContentHeight() {
-                return mContentHeight;
-            }
-        }
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadData("<html><body></body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.loadDataAndWaitForCompletion(
+                "<html><body></body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
         final int pageHeight = 600;
         // set the margin to 0
         final String p = "<p style=\"height:" + pageHeight
                 + "px;margin:0px auto;\">Get the height of HTML content.</p>";
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(mWebView.getHeight(), mWebView.getContentHeight() * mWebView.getScale(), 2f);
-                mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        assertEquals(mOnUiThread.getHeight(), mOnUiThread.getContentHeight() * mOnUiThread.getScale(), 2f);
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        HeightRunnable runnable = new HeightRunnable();
-        runTestOnUiThread(runnable);
-        assertTrue(runnable.getContentHeight() > pageHeight);
-        int extraSpace = runnable.getContentHeight() - pageHeight;
+        assertTrue(mOnUiThread.getContentHeight() > pageHeight);
+        int extraSpace = mOnUiThread.getContentHeight() - pageHeight;
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadData("<html><body>" + p + p + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + p + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(runnable);
-        assertEquals(pageHeight + pageHeight + extraSpace, runnable.getContentHeight());
+        assertEquals(pageHeight + pageHeight + extraSpace,
+                mOnUiThread.getContentHeight());
     }
 
     @TestTargetNew(
@@ -1594,8 +1403,7 @@
 
         startWebServer(false);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        mWebView.loadUrl(url);
-        waitForLoadComplete();
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
@@ -1679,50 +1487,35 @@
         args = {int.class, int.class}
     )
     public void testFlingScroll() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
-                int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
-                String p = "<p style=\"height:" + dimension + "px;" +
-                        "width:" + dimension + "px\">Test fling scroll.</p>";
-                mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
+        int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
+        String p = "<p style=\"height:" + dimension + "px;" +
+                "width:" + dimension + "px\">Test fling scroll.</p>";
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        ScrollRunnable runnable = new ScrollRunnable();
-        runTestOnUiThread(runnable);
-        int previousScrollX = runnable.getScrollX();
-        int previousScrollY = runnable.getScrollY();
+        int previousScrollX = mOnUiThread.getScrollX();
+        int previousScrollY = mOnUiThread.getScrollY();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.flingScroll(100, 100);
-            }
-        });
+        mOnUiThread.flingScroll(100, 100);
 
         int timeSlice = 500;
         Thread.sleep(timeSlice);
-        runTestOnUiThread(runnable);
-        assertTrue(runnable.getScrollX() > previousScrollX);
-        assertTrue(runnable.getScrollY() > previousScrollY);
+        assertTrue(mOnUiThread.getScrollX() > previousScrollX);
+        assertTrue(mOnUiThread.getScrollY() > previousScrollY);
 
-        previousScrollY = runnable.getScrollY();
-        previousScrollX = runnable.getScrollX();
+        previousScrollY = mOnUiThread.getScrollY();
+        previousScrollX = mOnUiThread.getScrollX();
         Thread.sleep(timeSlice);
-        runTestOnUiThread(runnable);
-        assertTrue(runnable.getScrollX() >= previousScrollX);
-        assertTrue(runnable.getScrollY() >= previousScrollY);
+        assertTrue(mOnUiThread.getScrollX() >= previousScrollX);
+        assertTrue(mOnUiThread.getScrollY() >= previousScrollY);
 
-        previousScrollY = runnable.getScrollY();
-        previousScrollX = runnable.getScrollX();
+        previousScrollY = mOnUiThread.getScrollY();
+        previousScrollX = mOnUiThread.getScrollX();
         Thread.sleep(timeSlice);
-        runTestOnUiThread(runnable);
-        assertTrue(runnable.getScrollX() >= previousScrollX);
-        assertTrue(runnable.getScrollY() >= previousScrollY);
+        assertTrue(mOnUiThread.getScrollX() >= previousScrollX);
+        assertTrue(mOnUiThread.getScrollY() >= previousScrollY);
     }
 
     @TestTargetNew(
@@ -1734,13 +1527,7 @@
         final String links = "<DL><p><DT><A HREF=\"" + TestHtmlConstants.HTML_URL1
                 + "\">HTML_URL1</A><DT><A HREF=\"" + TestHtmlConstants.HTML_URL2
                 + "\">HTML_URL2</A></DL><p>";
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadData("<html><body>" + links + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + links + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
         final HrefCheckHandler handler = new HrefCheckHandler(mWebView.getHandler().getLooper());
@@ -1750,12 +1537,7 @@
         // focus on first link
         handler.reset();
         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.requestFocusNodeHref(hrefMsg);
-            }
-        });
+        mOnUiThread.requestFocusNodeHref(hrefMsg);
         new PollingCheck() {
             @Override
             protected boolean check() {
@@ -1769,12 +1551,7 @@
         final Message hrefMsg2 = new Message();
         hrefMsg2.setTarget(handler);
         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.requestFocusNodeHref(hrefMsg2);
-            }
-        });
+        mOnUiThread.requestFocusNodeHref(hrefMsg2);
         new PollingCheck() {
             @Override
             protected boolean check() {
@@ -1783,12 +1560,7 @@
         }.run();
         assertEquals(TestHtmlConstants.HTML_URL2, handler.getResultUrl());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.requestFocusNodeHref(null);
-            }
-        });
+        mOnUiThread.requestFocusNodeHref(null);
     }
 
     @TestTargetNew(
@@ -1797,18 +1569,6 @@
         args = {android.os.Message.class}
     )
     public void testRequestImageRef() throws Exception, Throwable {
-        final class GetLocationRunnable implements Runnable {
-            private int[] mLocation;
-            @Override
-            public void run() {
-                mLocation = new int[2];
-                mWebView.getLocationOnScreen(mLocation);
-            }
-            public int[] getLocation() {
-                return mLocation;
-            }
-        }
-
         AssetManager assets = getActivity().getAssets();
         Bitmap bitmap = BitmapFactory.decodeStream(assets.open(TestHtmlConstants.LARGE_IMG_URL));
         int imgWidth = bitmap.getWidth();
@@ -1816,14 +1576,9 @@
 
         startWebServer(false);
         final String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.LARGE_IMG_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadData("<html><title>Title</title><body><img src=\"" + imgUrl
-                        + "\"/></body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.loadDataAndWaitForCompletion(
+                "<html><title>Title</title><body><img src=\"" + imgUrl
+                + "\"/></body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
         final HrefCheckHandler handler = new HrefCheckHandler(mWebView.getHandler().getLooper());
@@ -1832,9 +1587,7 @@
 
         // touch the image
         handler.reset();
-        GetLocationRunnable runnable = new GetLocationRunnable();
-        runTestOnUiThread(runnable);
-        int[] location = runnable.getLocation();
+        int[] location = mOnUiThread.getLocationOnScreen();
 
         long time = SystemClock.uptimeMillis();
         getInstrumentation().sendPointerSync(
@@ -1842,12 +1595,7 @@
                         location[0] + imgWidth / 2,
                         location[1] + imgHeight / 2, 0));
         getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.requestImageRef(msg);
-            }
-        });
+        mOnUiThread.requestImageRef(msg);
         new PollingCheck() {
             @Override
             protected boolean check() {
@@ -1873,17 +1621,6 @@
         args = {}
     )
     public void testGetHitTestResult() throws Throwable {
-        class HitTestResultRunnable implements Runnable {
-            private HitTestResult mHitTestResult;
-            @Override
-            public void run() {
-                mHitTestResult = mWebView.getHitTestResult();
-            }
-            public HitTestResult getHitTestResult() {
-                return mHitTestResult;
-            }
-        }
-
         final String anchor = "<p><a href=\"" + TestHtmlConstants.EXT_WEB_URL1
                 + "\">normal anchor</a></p>";
         final String blankAnchor = "<p><a href=\"\">blank anchor</a></p>";
@@ -1896,58 +1633,52 @@
         String location = "shanghai";
         final String geo = "<p><a href=\"geo:0,0?q=" + location + "\">Location</a></p>";
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadDataWithBaseURL("fake://home", "<html><body>" + anchor + blankAnchor + form
-                        + tel + mailto + geo + "</body></html>", "text/html", "UTF-8", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("fake://home",
+                "<html><body>" + anchor + blankAnchor + form + tel + mailto +
+                geo + "</body></html>", "text/html", "UTF-8", null);
         getInstrumentation().waitForIdleSync();
-        HitTestResultRunnable runnable = new HitTestResultRunnable();
 
         // anchor
         moveFocusDown();
-        runTestOnUiThread(runnable);
-        assertEquals(HitTestResult.SRC_ANCHOR_TYPE, runnable.getHitTestResult().getType());
-        assertEquals(TestHtmlConstants.EXT_WEB_URL1, runnable.getHitTestResult().getExtra());
+        HitTestResult hitTestResult = mOnUiThread.getHitTestResult();
+        assertEquals(HitTestResult.SRC_ANCHOR_TYPE, hitTestResult.getType());
+        assertEquals(TestHtmlConstants.EXT_WEB_URL1, hitTestResult.getExtra());
 
         // blank anchor
         moveFocusDown();
-        runTestOnUiThread(runnable);
-        assertEquals(HitTestResult.SRC_ANCHOR_TYPE, runnable.getHitTestResult().getType());
-        assertEquals("fake://home", runnable.getHitTestResult().getExtra());
+        hitTestResult = mOnUiThread.getHitTestResult();
+        assertEquals(HitTestResult.SRC_ANCHOR_TYPE, hitTestResult.getType());
+        assertEquals("fake://home", hitTestResult.getExtra());
 
         // text field
         moveFocusDown();
-        runTestOnUiThread(runnable);
-        assertEquals(HitTestResult.EDIT_TEXT_TYPE, runnable.getHitTestResult().getType());
-        assertNull(runnable.getHitTestResult().getExtra());
+        hitTestResult = mOnUiThread.getHitTestResult();
+        assertEquals(HitTestResult.EDIT_TEXT_TYPE, hitTestResult.getType());
+        assertNull(hitTestResult.getExtra());
 
         // submit button
         moveFocusDown();
-        runTestOnUiThread(runnable);
-        assertEquals(HitTestResult.UNKNOWN_TYPE, runnable.getHitTestResult().getType());
-        assertNull(runnable.getHitTestResult().getExtra());
+        hitTestResult = mOnUiThread.getHitTestResult();
+        assertEquals(HitTestResult.UNKNOWN_TYPE, hitTestResult.getType());
+        assertNull(hitTestResult.getExtra());
 
         // phone number
         moveFocusDown();
-        runTestOnUiThread(runnable);
-        assertEquals(HitTestResult.PHONE_TYPE, runnable.getHitTestResult().getType());
-        assertEquals(phoneNo, runnable.getHitTestResult().getExtra());
+        hitTestResult = mOnUiThread.getHitTestResult();
+        assertEquals(HitTestResult.PHONE_TYPE, hitTestResult.getType());
+        assertEquals(phoneNo, hitTestResult.getExtra());
 
         // email
         moveFocusDown();
-        runTestOnUiThread(runnable);
-        assertEquals(HitTestResult.EMAIL_TYPE, runnable.getHitTestResult().getType());
-        assertEquals(email, runnable.getHitTestResult().getExtra());
+        hitTestResult = mOnUiThread.getHitTestResult();
+        assertEquals(HitTestResult.EMAIL_TYPE, hitTestResult.getType());
+        assertEquals(email, hitTestResult.getExtra());
 
         // geo address
         moveFocusDown();
-        runTestOnUiThread(runnable);
-        assertEquals(HitTestResult.GEO_TYPE, runnable.getHitTestResult().getType());
-        assertEquals(location, runnable.getHitTestResult().getExtra());
+        hitTestResult = mOnUiThread.getHitTestResult();
+        assertEquals(HitTestResult.GEO_TYPE, hitTestResult.getType());
+        assertEquals(location, hitTestResult.getExtra());
     }
 
     @TestTargetNew(
@@ -1960,58 +1691,33 @@
         final float defaultScale =
             getInstrumentation().getTargetContext().getResources().getDisplayMetrics().density;
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(defaultScale, mWebView.getScale(), .01f);
+        assertEquals(defaultScale, mOnUiThread.getScale(), .01f);
 
-                mWebView.setInitialScale(0);
-                // modify content to fool WebKit into re-loading
-                mWebView.loadData("<html><body>" + p + "2" + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.setInitialScale(0);
+        // modify content to fool WebKit into re-loading
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "2" + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(defaultScale, mWebView.getScale(), .01f);
+        assertEquals(defaultScale, mOnUiThread.getScale(), .01f);
 
-                mWebView.setInitialScale(50);
-                mWebView.loadData("<html><body>" + p + "3" + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.setInitialScale(50);
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "3" + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(0.5f, mWebView.getScale(), .02f);
+        assertEquals(0.5f, mOnUiThread.getScale(), .02f);
 
-                mWebView.setInitialScale(0);
-                mWebView.loadData("<html><body>" + p + "4" + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        mOnUiThread.setInitialScale(0);
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "4" + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(defaultScale, mWebView.getScale(), .01f);
-            }
-        });
+        assertEquals(defaultScale, mOnUiThread.getScale(), .01f);
     }
 
     @TestTargetNew(
@@ -2025,7 +1731,7 @@
     public void testGetFavicon() throws Exception {
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.TEST_FAVICON_URL);
-        assertLoadUrlSuccessfully(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         mWebView.getFavicon();
         // ToBeFixed: Favicon is not loaded automatically.
         // assertNotNull(mWebView.getFavicon());
@@ -2043,13 +1749,13 @@
         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
 
-        assertLoadUrlSuccessfully(url1);
+        mOnUiThread.loadUrlAndWaitForCompletion(url1);
         pollingCheckWebBackForwardList(url1, 0, 1);
 
-        assertLoadUrlSuccessfully(url2);
+        mOnUiThread.loadUrlAndWaitForCompletion(url2);
         pollingCheckWebBackForwardList(url2, 1, 2);
 
-        assertLoadUrlSuccessfully(url3);
+        mOnUiThread.loadUrlAndWaitForCompletion(url3);
         pollingCheckWebBackForwardList(url3, 2, 3);
 
         mWebView.clearHistory();
@@ -2087,11 +1793,11 @@
         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
 
         // make a history list
-        assertLoadUrlSuccessfully(url1);
+        mOnUiThread.loadUrlAndWaitForCompletion(url1);
         pollingCheckWebBackForwardList(url1, 0, 1);
-        assertLoadUrlSuccessfully(url2);
+        mOnUiThread.loadUrlAndWaitForCompletion(url2);
         pollingCheckWebBackForwardList(url2, 1, 2);
-        assertLoadUrlSuccessfully(url3);
+        mOnUiThread.loadUrlAndWaitForCompletion(url3);
         pollingCheckWebBackForwardList(url3, 2, 3);
 
         // save the list
@@ -2148,6 +1854,9 @@
     public void testSetWebViewClient() throws Throwable {
         final class MockWebViewClient extends WaitForLoadedClient {
             private boolean mOnScaleChangedCalled = false;
+            public MockWebViewClient() {
+                super(mOnUiThread);
+            }
             @Override
             public void onScaleChanged(WebView view, float oldScale, float newScale) {
                 super.onScaleChanged(view, oldScale, newScale);
@@ -2159,21 +1868,11 @@
         }
 
         final MockWebViewClient webViewClient = new MockWebViewClient();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebViewClient(webViewClient);
-            }
-        });
+        mOnUiThread.setWebViewClient(webViewClient);
         getInstrumentation().waitForIdleSync();
         assertFalse(webViewClient.onScaleChangedCalled());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.zoomIn();
-            }
-        });
+        mOnUiThread.zoomIn();
         getInstrumentation().waitForIdleSync();
         assertTrue(webViewClient.onScaleChangedCalled());
     }
@@ -2210,32 +1909,15 @@
             args = {}
         )
     })
+    @UiThreadTest
     public void testInsecureSiteClearsCertificate() throws Throwable {
         final SslCertificate certificate =
                 new SslCertificate("foo", "bar", new Date(42), new Date(43));
         startWebServer(false);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.setCertificate(certificate);
-                mWebView.loadUrl(url);
-            }
-        });
-        waitForUiThreadDone();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                new PollingCheck(TEST_TIMEOUT) {
-                    @Override
-                    protected boolean check() {
-                        return mWebView.getCertificate() == null;
-                    }
-                }.run();
-            }
-        });
+        mWebView.setCertificate(certificate);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
+        assertNull(mWebView.getCertificate());
     }
 
     @TestTargets({
@@ -2250,8 +1932,12 @@
             args = {}
         )
     })
+    @UiThreadTest
     public void testSecureSiteSetsCertificate() throws Throwable {
         final class MockWebViewClient extends WaitForLoadedClient {
+            public MockWebViewClient() {
+                super(mOnUiThread);
+            }
             @Override
             public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                 handler.proceed();
@@ -2260,31 +1946,12 @@
 
         startWebServer(true);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebViewClient(new MockWebViewClient());
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.setCertificate(null);
-                mWebView.loadUrl(url);
-            }
-        });
-        waitForUiThreadDone();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                new PollingCheck(TEST_TIMEOUT) {
-                    @Override
-                    protected boolean check() {
-                        return mWebView.getCertificate() != null;
-                    }
-                }.run();
-                SslCertificate cert = mWebView.getCertificate();
-                assertNotNull(cert);
-                assertEquals("Android", cert.getIssuedTo().getUName());
-            }
-        });
+        mOnUiThread.setWebViewClient(new MockWebViewClient());
+        mWebView.setCertificate(null);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
+        SslCertificate cert = mWebView.getCertificate();
+        assertNotNull(cert);
+        assertEquals("Android", cert.getIssuedTo().getUName());
     }
 
     @TestTargetNew(
@@ -2307,6 +1974,10 @@
         final class MockWebViewClient extends WaitForLoadedClient {
             private String mErrorUrl;
             private WebView mWebView;
+
+            public MockWebViewClient() {
+                super(mOnUiThread);
+            }
             @Override
             public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                 mWebView = view;
@@ -2324,16 +1995,9 @@
         startWebServer(true);
         final String errorUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         final MockWebViewClient webViewClient = new MockWebViewClient();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebViewClient(webViewClient);
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.clearSslPreferences();
-                mWebView.loadUrl(errorUrl);
-            }
-        });
-        waitForUiThreadDone();
+        mOnUiThread.setWebViewClient(webViewClient);
+        mOnUiThread.clearSslPreferences();
+        mOnUiThread.loadUrlAndWaitForCompletion(errorUrl);
 
         assertEquals(mWebView, webViewClient.webView());
         assertEquals(errorUrl, webViewClient.errorUrl());
@@ -2346,6 +2010,9 @@
     )
     public void testOnReceivedSslErrorProceed() throws Throwable {
         final class MockWebViewClient extends WaitForLoadedClient {
+            public MockWebViewClient() {
+                super(mOnUiThread);
+            }
             @Override
             public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                 handler.proceed();
@@ -2354,21 +2021,9 @@
 
         startWebServer(true);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebViewClient(new MockWebViewClient());
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.loadUrl(url);
-            }
-        });
-        waitForUiThreadDone();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, mWebView.getTitle());
-            }
-        });
+        mOnUiThread.setWebViewClient(new MockWebViewClient());
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
+        assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, mOnUiThread.getTitle());
     }
 
     @TestTargetNew(
@@ -2378,6 +2033,9 @@
     )
     public void testOnReceivedSslErrorCancel() throws Throwable {
         final class MockWebViewClient extends WaitForLoadedClient {
+            public MockWebViewClient() {
+                super(mOnUiThread);
+            }
             @Override
             public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                 handler.cancel();
@@ -2386,22 +2044,10 @@
 
         startWebServer(true);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebViewClient(new MockWebViewClient());
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.clearSslPreferences();
-                mWebView.loadUrl(url);
-            }
-        });
-        waitForUiThreadDone();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertFalse(TestHtmlConstants.HELLO_WORLD_TITLE.equals(mWebView.getTitle()));
-            }
-        });
+        mOnUiThread.setWebViewClient(new MockWebViewClient());
+        mOnUiThread.clearSslPreferences();
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
+        assertFalse(TestHtmlConstants.HELLO_WORLD_TITLE.equals(mOnUiThread.getTitle()));
     }
 
     @TestTargetNew(
@@ -2415,36 +2061,18 @@
         final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient();
         startWebServer(true);
         final String firstUrl = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebViewClient(webViewClient);
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.clearSslPreferences();
-                mWebView.loadUrl(firstUrl);
-            }
-        });
-        waitForUiThreadDone();
+        mOnUiThread.setWebViewClient(webViewClient);
+        mOnUiThread.clearSslPreferences();
+        mOnUiThread.loadUrlAndWaitForCompletion(firstUrl);
         assertTrue(webViewClient.wasOnReceivedSslErrorCalled());
 
         // Load the second page. We don't expect a call to
         // WebViewClient.onReceivedSslError(), but the page should load.
         webViewClient.resetWasOnReceivedSslErrorCalled();
         final String sameHostUrl = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadUrl(sameHostUrl);
-            }
-        });
-        waitForUiThreadDone();
+        mOnUiThread.loadUrlAndWaitForCompletion(sameHostUrl);
         assertFalse(webViewClient.wasOnReceivedSslErrorCalled());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals("Second page", mWebView.getTitle());
-            }
-        });
+        assertEquals("Second page", mOnUiThread.getTitle());
     }
 
     @TestTargetNew(
@@ -2458,16 +2086,9 @@
         final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient();
         startWebServer(true);
         final String firstUrl = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebViewClient(webViewClient);
-                mWebView.setWebChromeClient(new LoadCompleteWebChromeClient());
-                mWebView.clearSslPreferences();
-                mWebView.loadUrl(firstUrl);
-            }
-        });
-        waitForUiThreadDone();
+        mOnUiThread.setWebViewClient(webViewClient);
+        mOnUiThread.clearSslPreferences();
+        mOnUiThread.loadUrlAndWaitForCompletion(firstUrl);
         assertTrue(webViewClient.wasOnReceivedSslErrorCalled());
 
         // Load the second page. We expect another call to
@@ -2477,20 +2098,9 @@
         // alias, but will be considered unique by the WebView.
         final String differentHostUrl = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2).replace(
                 "localhost", "127.0.0.1");
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadUrl(differentHostUrl);
-            }
-        });
-        waitForUiThreadDone();
+        mOnUiThread.loadUrlAndWaitForCompletion(differentHostUrl);
         assertTrue(webViewClient.wasOnReceivedSslErrorCalled());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals("Second page", mWebView.getTitle());
-            }
-        });
+        assertEquals("Second page", mOnUiThread.getTitle());
     }
 
     @TestTargetNew(
@@ -2499,33 +2109,23 @@
         args = {View.class, Rect.class, boolean.class}
     )
     public void testRequestChildRectangleOnScreen() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
-                final int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
-                String p = "<p style=\"height:" + dimension + "px;width:" + dimension + "px\">&nbsp;</p>";
-                mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
+        int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
+        String p = "<p style=\"height:" + dimension + "px;width:" + dimension + "px\">&nbsp;</p>";
+        mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+                + "</body></html>", "text/html", null);
         getInstrumentation().waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int origX = mWebView.getScrollX();
-                int origY = mWebView.getScrollY();
+        int origX = mOnUiThread.getScrollX();
+        int origY = mOnUiThread.getScrollY();
 
-                DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
-                final int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
-                int half = dimension / 2;
-                Rect rect = new Rect(half, half, half + 1, half + 1);
-                assertTrue(mWebView.requestChildRectangleOnScreen(mWebView, rect, true));
-                assertTrue(mWebView.getScrollX() > origX);
-                assertTrue(mWebView.getScrollY() > origY);
-            }
-        });
+        metrics = mOnUiThread.getDisplayMetrics();
+        dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
+        int half = dimension / 2;
+        Rect rect = new Rect(half, half, half + 1, half + 1);
+        assertTrue(mOnUiThread.requestChildRectangleOnScreen(mWebView, rect, true));
+        assertTrue(mOnUiThread.getScrollX() > origX);
+        assertTrue(mOnUiThread.getScrollY() > origY);
     }
 
     @TestTargets({
@@ -2567,28 +2167,18 @@
         startWebServer(false);
         final String url = mWebServer.getBinaryUrl(mimeType, length);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // By default, WebView sends an intent to ask the system to
-                // handle loading a new URL. We set WebViewClient as
-                // WebViewClient.shouldOverrideUrlLoading() returns false, so
-                // the WebView will load the new URL.
-                mWebView.setWebViewClient(new WaitForLoadedClient());
-                mWebView.setDownloadListener(listener);
-                mWebView.loadData("<html><body><a href=\"" + url + "\">link</a></body></html>",
-                        "text/html", null);
-                waitForLoadComplete();
-            }
-        });
+        // By default, WebView sends an intent to ask the system to
+        // handle loading a new URL. We set WebViewClient as
+        // WebViewClient.shouldOverrideUrlLoading() returns false, so
+        // the WebView will load the new URL.
+        mOnUiThread.setDownloadListener(listener);
+        mOnUiThread.loadDataAndWaitForCompletion(
+                "<html><body><a href=\"" + url
+                + "\">link</a></body></html>",
+                "text/html", null);
         // Wait for layout to complete before setting focus.
         getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(mWebView.requestFocus(View.FOCUS_DOWN, null));
-            }
-        });
+        assertTrue(mOnUiThread.requestFocus(View.FOCUS_DOWN, null));
         getInstrumentation().waitForIdleSync();
         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
         new PollingCheck(TEST_TIMEOUT) {
@@ -2639,17 +2229,15 @@
         settings.setJavaScriptEnabled(true);
         startWebServer(false);
         String url = mWebServer.getAssetUrl(TestHtmlConstants.NETWORK_STATE_URL);
-        assertLoadUrlSuccessfully(url);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         assertEquals("ONLINE", mWebView.getTitle());
 
         mWebView.setNetworkAvailable(false);
-        mWebView.reload();
-        waitForLoadComplete();
+        mOnUiThread.reloadAndWaitForCompletion();
         assertEquals("OFFLINE", mWebView.getTitle());
 
         mWebView.setNetworkAvailable(true);
-        mWebView.reload();
-        waitForLoadComplete();
+        mOnUiThread.reloadAndWaitForCompletion();
         assertEquals("ONLINE", mWebView.getTitle());
     }
 
@@ -2661,6 +2249,11 @@
     public void testSetWebChromeClient() throws Throwable {
         final class MockWebChromeClient extends WaitForProgressClient {
             private boolean mOnProgressChanged = false;
+
+            public MockWebChromeClient() {
+                super(mOnUiThread);
+            }
+
             @Override
             public void onProgressChanged(WebView view, int newProgress) {
                 super.onProgressChanged(view, newProgress);
@@ -2673,23 +2266,13 @@
 
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.setWebChromeClient(webChromeClient);
-            }
-        });
+        mOnUiThread.setWebChromeClient(webChromeClient);
         getInstrumentation().waitForIdleSync();
         assertFalse(webChromeClient.onProgressChangedCalled());
 
         startWebServer(false);
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadUrl(url);
-            }
-        });
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
         getInstrumentation().waitForIdleSync();
 
         new PollingCheck(TEST_TIMEOUT) {
@@ -2737,7 +2320,7 @@
             }
         };
         final Monitor monitor = new Monitor();
-        final String updateMonitorHtml = "<html><head></head>" +
+        final String updateMonitorHtml = "<html>" +
                 "<body onload=\"monitor.update();\"></body></html>";
 
         // Test that JavaScript is executed even with timers paused.
@@ -2747,27 +2330,20 @@
                 mWebView.getSettings().setJavaScriptEnabled(true);
                 mWebView.addJavascriptInterface(monitor, "monitor");
                 mWebView.pauseTimers();
-                mWebView.loadData(updateMonitorHtml, "text/html", null);
+                mOnUiThread.loadDataAndWaitForCompletion(updateMonitorHtml,
+                        "text/html", null);
             }
         });
         assertTrue(monitor.waitForUpdate());
 
         // Start a timer and test that it does not fire.
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.loadUrl("javascript:setTimeout(function(){monitor.update();},100)");
-            }
-        });
+        mOnUiThread.loadDataAndWaitForCompletion(
+                "<html><body onload='setTimeout(function(){monitor.update();},100)'>" +
+                "</body></html>", "text/html", null);
         assertFalse(monitor.waitForUpdate());
 
         // Resume timers and test that the timer fires.
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mWebView.resumeTimers();
-            }
-        });
+        mOnUiThread.resumeTimers();
         assertTrue(monitor.waitForUpdate());
     }
 
@@ -2909,22 +2485,6 @@
         Thread.sleep(500);
     }
 
-    private final class ScrollRunnable implements Runnable {
-        private int mScrollX;
-        private int mScrollY;
-        @Override
-        public void run() {
-            mScrollX = mWebView.getScrollX();
-            mScrollY = mWebView.getScrollY();
-        }
-        public int getScrollX() {
-            return mScrollX;
-        }
-        public int getScrollY() {
-            return mScrollY;
-        }
-    }
-
     private void pollingCheckWebBackForwardList(final String currUrl, final int currIndex,
             final int size) {
         new PollingCheck() {
@@ -3017,46 +2577,13 @@
         return true;
     }
 
-    private void assertLoadUrlSuccessfully(String url) {
-        mWebView.loadUrl(url);
-        waitForLoadComplete();
-    }
-
-    private void waitForLoadComplete() {
-        WaitForLoadUrl.getInstance().waitForLoadComplete(mWebView);
-    }
-
-    private synchronized void notifyUiThreadDone() {
-        mIsUiThreadDone = true;
-        notify();
-    }
-
-    private synchronized void waitForUiThreadDone() throws InterruptedException {
-        while (!mIsUiThreadDone) {
-            try {
-                wait(TEST_TIMEOUT);
-            } catch (InterruptedException e) {
-                continue;
-            }
-            if (!mIsUiThreadDone) {
-                Assert.fail("Unexpected timeout");
-            }
-        }
-    }
-
-    final class LoadCompleteWebChromeClient extends WaitForProgressClient {
-        @Override
-        public void onProgressChanged(WebView webView, int progress) {
-            super.onProgressChanged(webView, progress);
-            if (progress == 100) {
-                notifyUiThreadDone();
-            }
-        }
-    }
-
     // Note that this class is not thread-safe.
     final class SslErrorWebViewClient extends WaitForLoadedClient {
         private boolean mWasOnReceivedSslErrorCalled;
+
+        public SslErrorWebViewClient() {
+            super(mOnUiThread);
+        }
         @Override
         public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
             mWasOnReceivedSslErrorCalled = true;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
index 4bebf84..bbe1fd3 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
@@ -17,6 +17,7 @@
 package android.webkit.cts;
 
 import android.test.AndroidTestCase;
+import android.test.UiThreadTest;
 import android.webkit.WebView;
 import android.webkit.WebView.WebViewTransport;
 
@@ -39,6 +40,7 @@
             args = {}
         )
     })
+    @UiThreadTest
     public void testAccessWebView() {
         WebView webView = new WebView(mContext);
         WebViewTransport transport = webView.new WebViewTransport();
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index a35120e..628935c 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -31,5 +31,4 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
-include $(BUILD_PACKAGE)
-
+include $(BUILD_CTS_PACKAGE)
diff --git a/tools/build/test_executable.mk b/tools/build/test_executable.mk
index b1889a8..8b445a3 100644
--- a/tools/build/test_executable.mk
+++ b/tools/build/test_executable.mk
@@ -25,16 +25,18 @@
 
 include $(BUILD_EXECUTABLE)
 
-cts_executable_xml := $(CTS_NATIVE_XML_OUT)/$(LOCAL_MODULE).xml
+cts_executable_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
 
 $(cts_executable_xml): PRIVATE_PATH := $(LOCAL_PATH)
 $(cts_executable_xml): PRIVATE_TEST_PACKAGE := $(LOCAL_CTS_TEST_PACKAGE)
 $(cts_executable_xml): PRIVATE_EXECUTABLE := $(LOCAL_MODULE)
-$(cts_executable_xml): $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES)) $(CTS_EXPECTATIONS) | $(CTS_NATIVE_TEST_SCANNER) $(CTS_XML_GENERATOR)
+$(cts_executable_xml): $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES)) $(CTS_EXPECTATIONS) $(CTS_NATIVE_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for native package $(PRIVATE_TEST_PACKAGE)
-	$(hide) mkdir -p $(CTS_NATIVE_XML_OUT)
-	$(hide) $(CTS_NATIVE_TEST_SCANNER) -s $(PRIVATE_PATH) | \
-			$(CTS_XML_GENERATOR) -n $(PRIVATE_EXECUTABLE) \
+	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
+	$(hide) $(CTS_NATIVE_TEST_SCANNER) -s $(PRIVATE_PATH) \
+						-t $(PRIVATE_TEST_PACKAGE) | \
+			$(CTS_XML_GENERATOR) -t native \
+						-n $(PRIVATE_EXECUTABLE) \
 						-p $(PRIVATE_TEST_PACKAGE) \
 						-e $(CTS_EXPECTATIONS) \
 						-o $@
diff --git a/tools/build/test_host_java_library.mk b/tools/build/test_host_java_library.mk
new file mode 100644
index 0000000..9512bfa
--- /dev/null
+++ b/tools/build/test_host_java_library.mk
@@ -0,0 +1,38 @@
+# 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.
+
+#
+# Builds a host library and defines a rule to generate the associated test
+# package XML needed by CTS.
+#
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
+
+$(cts_library_xml): PRIVATE_PATH := $(LOCAL_PATH)/src
+$(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_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) -s $(PRIVATE_PATH) \
+						-d $(CTS_JAVA_TEST_SCANNER_DOCLET) | \
+			$(CTS_XML_GENERATOR) -t hostSideOnly \
+						-j $(PRIVATE_JAR_PATH) \
+						-n $(PRIVATE_LIBRARY) \
+						-p $(PRIVATE_TEST_PACKAGE) \
+						-e $(CTS_EXPECTATIONS) \
+						-o $@
diff --git a/tools/build/test_package.mk b/tools/build/test_package.mk
new file mode 100644
index 0000000..1cf4ecc
--- /dev/null
+++ b/tools/build/test_package.mk
@@ -0,0 +1,47 @@
+# 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.
+
+#
+# Builds a package and defines a rule to generate the associated test
+# package XML needed by CTS.
+#
+# Replace "include $(BUILD_PACKAGE)" with "include $(BUILD_CTS_PACKAGE)"
+#
+
+include $(BUILD_PACKAGE)
+
+cts_package_apk := $(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).apk
+cts_package_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).xml
+
+$(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_INSTRUMENTATION := $(LOCAL_INSTRUMENTATION_FOR)
+$(cts_package_xml): PRIVATE_PACKAGE := $(LOCAL_PACKAGE_NAME)
+$(cts_package_xml): PRIVATE_TEST_PACKAGE := android.$(notdir $(LOCAL_PATH))
+$(cts_package_xml): PRIVATE_MANIFEST := $(LOCAL_PATH)/AndroidManifest.xml
+$(cts_package_xml): $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/package.apk $(CTS_EXPECTATIONS) $(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) -s $(PRIVATE_PATH) \
+						-d $(CTS_JAVA_TEST_SCANNER_DOCLET) | \
+			$(CTS_XML_GENERATOR) -m $(PRIVATE_MANIFEST) \
+						-i "$(PRIVATE_INSTRUMENTATION)" \
+						-n $(PRIVATE_PACKAGE) \
+						-p $(PRIVATE_TEST_PACKAGE) \
+						-e $(CTS_EXPECTATIONS) \
+						-o $@
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
index de2e3eb..101be7f 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
@@ -26,22 +26,31 @@
 
     private final String mName;
 
+    private final boolean mDeprecated;
+
     private final List<ApiConstructor> mApiConstructors = new ArrayList<ApiConstructor>();
 
     private final List<ApiMethod> mApiMethods = new ArrayList<ApiMethod>();
 
-    ApiClass(String name) {
-        this.mName = name;
+    ApiClass(String name, boolean deprecated) {
+        mName = name;
+        mDeprecated = deprecated;
     }
 
+    @Override
     public int compareTo(ApiClass another) {
         return mName.compareTo(another.mName);
     }
 
+    @Override
     public String getName() {
         return mName;
     }
 
+    public boolean isDeprecated() {
+        return mDeprecated;
+    }
+
     public void addConstructor(ApiConstructor constructor) {
         mApiConstructors.add(constructor);
     }
@@ -97,6 +106,7 @@
         return mApiConstructors.size() + mApiMethods.size();
     }
 
+    @Override
     public float getCoveragePercentage() {
         return (float) getNumCoveredMethods() / getTotalMethods() * 100;
     }
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiConstructor.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiConstructor.java
index b38bd34..8d721e6 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiConstructor.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiConstructor.java
@@ -27,13 +27,17 @@
 
     private final List<String> mParameterTypes;
 
+    private final boolean mDeprecated;
+
     private boolean mIsCovered;
 
-    ApiConstructor(String name, List<String> parameterTypes) {
-        this.mName = name;
-        this.mParameterTypes = new ArrayList<String>(parameterTypes);
+    ApiConstructor(String name, List<String> parameterTypes, boolean deprecated) {
+        mName = name;
+        mParameterTypes = new ArrayList<String>(parameterTypes);
+        mDeprecated = deprecated;
     }
 
+    @Override
     public int compareTo(ApiConstructor another) {
         return mParameterTypes.size() - another.mParameterTypes.size();
     }
@@ -46,6 +50,10 @@
         return Collections.unmodifiableList(mParameterTypes);
     }
 
+    public boolean isDeprecated() {
+        return mDeprecated;
+    }
+
     public boolean isCovered() {
         return mIsCovered;
     }
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java
index eb67b8e..053cd12 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java
@@ -29,14 +29,18 @@
 
     private final String mReturnType;
 
+    private boolean mDeprecated;
+
     private boolean mIsCovered;
 
-    ApiMethod(String name, List<String> parameterTypes, String returnType) {
-        this.mName = name;
-        this.mParameterTypes = new ArrayList<String>(parameterTypes);
-        this.mReturnType = returnType;
+    ApiMethod(String name, List<String> parameterTypes, String returnType, boolean deprecated) {
+        mName = name;
+        mParameterTypes = new ArrayList<String>(parameterTypes);
+        mReturnType = returnType;
+        mDeprecated = deprecated;
     }
 
+    @Override
     public int compareTo(ApiMethod another) {
         return mName.compareTo(another.mName);
     }
@@ -53,6 +57,10 @@
         return mReturnType;
     }
 
+    public boolean isDeprecated() {
+        return mDeprecated;
+    }
+
     public boolean isCovered() {
         return mIsCovered;
     }
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
index f0ca889..ddc6fb4 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
@@ -29,9 +29,10 @@
     private final Map<String, ApiClass> mApiClassMap = new HashMap<String, ApiClass>();
 
     ApiPackage(String name) {
-        this.mName = name;
+        mName = name;
     }
 
+    @Override
     public String getName() {
         return mName;
     }
@@ -64,6 +65,7 @@
         return total;
     }
 
+    @Override
     public float getCoveragePercentage() {
         return (float) getNumCoveredMethods() / getTotalMethods() * 100;
     }
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
index 5768e6c..f3abd86 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
@@ -36,6 +36,8 @@
 
     private String mCurrentMethodReturnType;
 
+    private boolean mDeprecated;
+
     private List<String> mCurrentParameterTypes = new ArrayList<String>();
 
     private ApiCoverage mApiCoverage = new ApiCoverage();
@@ -49,27 +51,30 @@
             throws SAXException {
         super.startElement(uri, localName, name, attributes);
         if ("package".equalsIgnoreCase(localName)) {
-            mCurrentPackageName = CurrentXmlHandler.getValue(attributes, "name");
+            mCurrentPackageName = getValue(attributes, "name");
 
             ApiPackage apiPackage = new ApiPackage(mCurrentPackageName);
             mApiCoverage.addPackage(apiPackage);
 
         } else if ("class".equalsIgnoreCase(localName)
                 || "interface".equalsIgnoreCase(localName)) {
-            mCurrentClassName = CurrentXmlHandler.getValue(attributes, "name");
+            mCurrentClassName = getValue(attributes, "name");
+            mDeprecated = isDeprecated(attributes);
 
-            ApiClass apiClass = new ApiClass(mCurrentClassName);
+            ApiClass apiClass = new ApiClass(mCurrentClassName, mDeprecated);
             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
             apiPackage.addClass(apiClass);
 
         } else if ("constructor".equalsIgnoreCase(localName)) {
+            mDeprecated = isDeprecated(attributes);
             mCurrentParameterTypes.clear();
         }  else if ("method".equalsIgnoreCase(localName)) {
-            mCurrentMethodName = CurrentXmlHandler.getValue(attributes, "name");
-            mCurrentMethodReturnType = CurrentXmlHandler.getValue(attributes, "return");
+            mDeprecated = isDeprecated(attributes);
+            mCurrentMethodName = getValue(attributes, "name");
+            mCurrentMethodReturnType = getValue(attributes, "return");
             mCurrentParameterTypes.clear();
         } else if ("parameter".equalsIgnoreCase(localName)) {
-            mCurrentParameterTypes.add(CurrentXmlHandler.getValue(attributes, "type"));
+            mCurrentParameterTypes.add(getValue(attributes, "type"));
         }
     }
 
@@ -82,13 +87,13 @@
                 return;
             }
             ApiConstructor apiConstructor = new ApiConstructor(mCurrentClassName,
-                    mCurrentParameterTypes);
+                    mCurrentParameterTypes, mDeprecated);
             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
             ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
             apiClass.addConstructor(apiConstructor);
         }  else if ("method".equalsIgnoreCase(localName)) {
             ApiMethod apiMethod = new ApiMethod(mCurrentMethodName, mCurrentParameterTypes,
-                    mCurrentMethodReturnType);
+                    mCurrentMethodReturnType, mDeprecated);
             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
             ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
             apiClass.addMethod(apiMethod);
@@ -101,4 +106,8 @@
                 .replaceAll("<.+>", "")
                 .replace("$", ".");
     }
+
+    private boolean isDeprecated(Attributes attributes) {
+        return "deprecated".equals(attributes.getValue("deprecated"));
+    }
 }
\ No newline at end of file
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/HtmlReport.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/HtmlReport.java
index de9b7a6..9243fe0 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/HtmlReport.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/HtmlReport.java
@@ -37,11 +37,12 @@
 class HtmlReport {
 
     public static void printHtmlReport(final List<File> testApks, final ApiCoverage apiCoverage,
-            final OutputStream out) throws IOException, TransformerException, InterruptedException {
+            final OutputStream out) throws IOException, TransformerException {
         final PipedOutputStream xmlOut = new PipedOutputStream();
         final PipedInputStream xmlIn = new PipedInputStream(xmlOut);
 
         Thread t = new Thread(new Runnable() {
+            @Override
             public void run() {
                 XmlReport.printXmlReport(testApks, apiCoverage, xmlOut);
 
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
index 68acf06..94ccbb4 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
@@ -72,12 +72,14 @@
                         out.println("<class name=\"" + apiClass.getName()
                                 + "\" numCovered=\"" + apiClass.getNumCoveredMethods()
                                 + "\" numTotal=\"" + apiClass.getTotalMethods()
+                                + "\" deprecated=\"" + apiClass.isDeprecated()
                                 + "\" coveragePercentage=\""
                                     + Math.round(apiClass.getCoveragePercentage())
                                 + "\">");
 
                         for (ApiConstructor constructor : apiClass.getConstructors()) {
                             out.println("<constructor name=\"" + constructor.getName()
+                                    + "\" deprecated=\"" + constructor.isDeprecated()
                                     + "\" covered=\"" + constructor.isCovered() + "\">");
 
                             for (String parameterType : constructor.getParameterTypes()) {
@@ -90,6 +92,7 @@
                         for (ApiMethod method : apiClass.getMethods()) {
                             out.println("<method name=\"" + method.getName()
                                     + "\" returnType=\"" + method.getReturnType()
+                                    + "\" deprecated=\"" + method.isDeprecated()
                                     + "\" covered=\"" + method.isCovered() + "\">");
 
                             for (String parameterType : method.getParameterTypes()) {
diff --git a/tools/cts-api-coverage/src/res/api-coverage.xsl b/tools/cts-api-coverage/src/res/api-coverage.xsl
index 3743580..95994e2 100644
--- a/tools/cts-api-coverage/src/res/api-coverage.xsl
+++ b/tools/cts-api-coverage/src/res/api-coverage.xsl
@@ -71,6 +71,10 @@
                     .green {
                         background-color: #66FF66;
                     }
+
+                    .deprecated {
+                        text-decoration: line-through;
+                    }
                 </style>
             </head>
             <body>
@@ -118,7 +122,7 @@
     
     <xsl:template name="packageOrClassListItem">
         <xsl:param name="bulletClass" />
-        
+
         <xsl:variable name="colorClass">
             <xsl:choose>
                 <xsl:when test="@coveragePercentage &lt;= 50">red</xsl:when>
@@ -127,8 +131,15 @@
             </xsl:choose>
         </xsl:variable>
         
+        <xsl:variable name="deprecatedClass">
+            <xsl:choose>
+                <xsl:when test="@deprecated = 'true'">deprecated</xsl:when>
+                <xsl:otherwise></xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+
         <li class="{$bulletClass}" onclick="toggleVisibility('{@name}')">
-            <span class="{$colorClass}">
+            <span class="{$colorClass} {$deprecatedClass}">
                 <b><xsl:value-of select="@name" /></b>
                 &nbsp;<xsl:value-of select="@coveragePercentage" />%
                 &nbsp;(<xsl:value-of select="@numCovered" />/<xsl:value-of select="@numTotal" />)
@@ -137,7 +148,15 @@
     </xsl:template>
   
   <xsl:template name="methodListItem">
-    <span class="method">
+
+    <xsl:variable name="deprecatedClass">
+        <xsl:choose>
+            <xsl:when test="@deprecated = 'true'">deprecated</xsl:when>
+            <xsl:otherwise></xsl:otherwise>
+        </xsl:choose>
+    </xsl:variable>
+
+    <span class="method {$deprecatedClass}">
       <xsl:choose>
         <xsl:when test="@covered = 'true'">[X]</xsl:when>
         <xsl:otherwise>[ ]</xsl:otherwise>
@@ -147,7 +166,7 @@
     </span>
     <br />
   </xsl:template>
-  
+
   <xsl:template name="formatParameters">(<xsl:for-each select="parameter">
       <xsl:value-of select="@type" />
       <xsl:if test="not(position() = last())">,&nbsp;</xsl:if>
diff --git a/CtsHostLibraryList.mk b/tools/cts-java-scanner-doclet/Android.mk
similarity index 61%
rename from CtsHostLibraryList.mk
rename to tools/cts-java-scanner-doclet/Android.mk
index ac9a700..51b141e 100644
--- a/CtsHostLibraryList.mk
+++ b/tools/cts-java-scanner-doclet/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 The Android Open Source Project
+# 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.
@@ -12,4 +12,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-CTS_HOST_LIBRARY_JARS := 
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cts-java-scanner-doclet
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR) cts/tools/utils/lib/junit.jar
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java b/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
new file mode 100644
index 0000000..808473a
--- /dev/null
+++ b/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
@@ -0,0 +1,101 @@
+/*
+ * 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.javascannerdoclet;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.AnnotationValue;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.Doclet;
+import com.sun.javadoc.MethodDoc;
+import com.sun.javadoc.RootDoc;
+import com.sun.javadoc.AnnotationDesc.ElementValuePair;
+
+/**
+ * Doclet that outputs in the following format:
+ *
+ * suite:android.holo.cts
+ * case:HoloTest
+ * test:testHolo
+ * test:testHoloDialog
+ */
+public class CtsJavaScannerDoclet extends Doclet {
+
+    static final String JUNIT_TEST_CASE_CLASS_NAME = "junit.framework.testcase";
+
+    public static boolean start(RootDoc root) {
+        ClassDoc[] classes = root.classes();
+        if (classes == null) {
+            return false;
+        }
+
+        PrintWriter writer = new PrintWriter(System.out);
+
+        for (ClassDoc clazz : classes) {
+            if (clazz.isAbstract() || !isValidJUnitTestCase(clazz)) {
+                continue;
+            }
+            writer.append("suite:").println(clazz.containingPackage().name());
+            writer.append("case:").println(clazz.name());
+            for (; clazz != null; clazz = clazz.superclass()) {
+                for (MethodDoc method : clazz.methods()) {
+                    if (!method.name().startsWith("test")) {
+                        continue;
+                    }
+                    writer.append("test:").println(method.name());
+                }
+            }
+        }
+
+        writer.close();
+        return true;
+    }
+
+    private static boolean isValidJUnitTestCase(ClassDoc clazz) {
+        while((clazz = clazz.superclass()) != null) {
+            if (JUNIT_TEST_CASE_CLASS_NAME.equals(clazz.qualifiedName().toLowerCase())) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/tools/cts-java-scanner/Android.mk b/tools/cts-java-scanner/Android.mk
new file mode 100644
index 0000000..8b6c906
--- /dev/null
+++ b/tools/cts-java-scanner/Android.mk
@@ -0,0 +1,43 @@
+# 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)
+
+# We use copy-file-to-new-target so that the installed
+# script file's timestamp is at least as new as the
+# .jar file it wraps.
+
+# the hat script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := cts-java-scanner
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/$(LOCAL_MODULE) | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+# the other stuff
+# ============================================================
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+		src \
+	))
+
+include $(subdirs)
diff --git a/tools/cts-java-scanner/etc/cts-java-scanner b/tools/cts-java-scanner/etc/cts-java-scanner
new file mode 100644
index 0000000..378eee8
--- /dev/null
+++ b/tools/cts-java-scanner/etc/cts-java-scanner
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+libdir=`dirname $progdir`/framework
+
+javaOpts=""
+while expr "x$1" : 'x-J' >/dev/null; do
+    opt=`expr "$1" : '-J\(.*\)'`
+    javaOpts="${javaOpts} -${opt}"
+    shift
+done
+
+exec java $javaOpts -jar $libdir/cts-java-scanner.jar "$@"
diff --git a/tools/cts-java-scanner/src/Android.mk b/tools/cts-java-scanner/src/Android.mk
new file mode 100644
index 0000000..ec42bcf
--- /dev/null
+++ b/tools/cts-java-scanner/src/Android.mk
@@ -0,0 +1,28 @@
+# 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)
+
+
+# cts-java-scanner java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAR_MANIFEST := MANIFEST.mf
+
+LOCAL_MODULE := cts-java-scanner
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-java-scanner/src/MANIFEST.mf b/tools/cts-java-scanner/src/MANIFEST.mf
new file mode 100644
index 0000000..642f226
--- /dev/null
+++ b/tools/cts-java-scanner/src/MANIFEST.mf
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.android.cts.javascanner.CtsJavaScanner
diff --git a/tools/cts-java-scanner/src/com/android/cts/javascanner/CtsJavaScanner.java b/tools/cts-java-scanner/src/com/android/cts/javascanner/CtsJavaScanner.java
new file mode 100644
index 0000000..a843fc6
--- /dev/null
+++ b/tools/cts-java-scanner/src/com/android/cts/javascanner/CtsJavaScanner.java
@@ -0,0 +1,71 @@
+/*
+ * 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.javascanner;
+
+import java.io.File;
+import java.util.Arrays;
+
+/**
+ * Class that searches a source directory for native gTests and outputs a
+ * list of test classes and methods.
+ */
+public class CtsJavaScanner {
+
+    private static void usage(String[] args) {
+        System.err.println("Arguments: " + Arrays.asList(args));
+        System.err.println("Usage: cts-java-scanner -s SOURCE_DIR -d DOCLET_PATH");
+        System.exit(1);
+    }
+
+    public static void main(String[] args) throws Exception {
+        File sourceDir = null;
+        File docletPath = null;
+
+        for (int i = 0; i < args.length; i++) {
+            if ("-s".equals(args[i])) {
+                sourceDir = new File(getArg(args, ++i, "Missing value for source directory"));
+            } else if ("-d".equals(args[i])) {
+                docletPath = new File(getArg(args, ++i, "Missing value for docletPath"));
+            } else {
+                System.err.println("Unsupported flag: " + args[i]);
+                usage(args);
+            }
+        }
+
+        if (sourceDir == null) {
+            System.err.println("Source directory is required");
+            usage(args);
+        }
+
+        if (docletPath == null) {
+            System.err.println("Doclet path is required");
+            usage(args);
+        }
+
+        DocletRunner runner = new DocletRunner(sourceDir, docletPath);
+        System.exit(runner.runJavaDoc());
+    }
+
+    private static String getArg(String[] args, int index, String message) {
+        if (index < args.length) {
+            return args[index];
+        } else {
+            System.err.println(message);
+            usage(args);
+            return null;
+        }
+    }
+}
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
new file mode 100644
index 0000000..8a371fd
--- /dev/null
+++ b/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
@@ -0,0 +1,114 @@
+/*
+ * 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.javascanner;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+class DocletRunner {
+
+    private final File mSourceDir;
+    private final File mDocletPath;
+
+    DocletRunner(File sourceDir, File docletPath) {
+        mSourceDir = sourceDir;
+        mDocletPath = docletPath;
+    }
+
+    int runJavaDoc() throws IOException, InterruptedException {
+        List<String> args = new ArrayList<String>();
+        args.add("javadoc");
+        args.add("-doclet");
+        args.add("com.android.cts.javascannerdoclet.CtsJavaScannerDoclet");
+        args.add("-docletpath");
+        args.add(mDocletPath.toString());
+        args.add("-sourcepath");
+        args.add(getSourcePath(mSourceDir));
+        args.add("-classpath");
+        args.add(getClassPath());
+        args.addAll(getSourceFiles(mSourceDir));
+
+        Process process = new ProcessBuilder(args).start();
+        Scanner scanner = null;
+        try {
+            scanner = new Scanner(process.getInputStream());
+            while (scanner.hasNextLine()) {
+                System.out.println(scanner.nextLine());
+            }
+        } finally {
+            if (scanner != null) {
+                scanner.close();
+            }
+        }
+
+        return process.waitFor();
+    }
+
+    private String getSourcePath(File sourceDir) {
+        List<String> sourcePath = new ArrayList<String>();
+        sourcePath.add("./frameworks/base/core/java");
+        sourcePath.add("./frameworks/base/test-runner/src");
+        sourcePath.add("./libcore/junit/src/main/java");
+        sourcePath.add("./development/tools/hosttestlib/src");
+        sourcePath.add("./libcore/dalvik/src/main/java");
+        sourcePath.add("./cts/tests/src");
+        sourcePath.add(sourceDir.toString());
+        return join(sourcePath, ":");
+    }
+
+    private String getClassPath() {
+        List<String> classPath = new ArrayList<String>();
+        classPath.add("./prebuilt/common/tradefed/tradefed-prebuilt.jar");
+        return join(classPath, ":");
+    }
+
+    private List<String> getSourceFiles(File sourceDir) {
+        List<String> sourceFiles = new ArrayList<String>();
+
+        File[] files = sourceDir.listFiles(new FileFilter() {
+            @Override
+            public boolean accept(File pathname) {
+                return pathname.isDirectory() || pathname.toString().endsWith(".java");
+            }
+        });
+
+        for (File file : files) {
+            if (file.isDirectory()) {
+                sourceFiles.addAll(getSourceFiles(file));
+            } else {
+                sourceFiles.add(file.toString());
+            }
+        }
+
+        return sourceFiles;
+    }
+
+    private String join(List<String> options, String delimiter) {
+        StringBuilder builder = new StringBuilder();
+        int numOptions = options.size();
+        for (int i = 0; i < numOptions; i++) {
+            builder.append(options.get(i));
+            if (i + 1 < numOptions) {
+                builder.append(delimiter);
+            }
+        }
+        return builder.toString();
+    }
+}
diff --git a/tools/cts-native-scanner/src/com/android/cts/nativescanner/CtsNativeScanner.java b/tools/cts-native-scanner/src/com/android/cts/nativescanner/CtsNativeScanner.java
index 0eb757e..a7599b0 100644
--- a/tools/cts-native-scanner/src/com/android/cts/nativescanner/CtsNativeScanner.java
+++ b/tools/cts-native-scanner/src/com/android/cts/nativescanner/CtsNativeScanner.java
@@ -27,21 +27,19 @@
 
     private static void usage(String[] args) {
         System.err.println("Arguments: " + Arrays.asList(args));
-        System.err.println("Usage: cts-native-scanner -s SOURCE_DIR");
+        System.err.println("Usage: cts-native-scanner -s SOURCE_DIR -t TEST_SUITE");
         System.exit(1);
     }
 
     public static void main(String[] args) throws Exception {
         File sourceDir = null;
+        String testSuite = null;
 
         for (int i = 0; i < args.length; i++) {
             if ("-s".equals(args[i])) {
-                if (i + 1 < args.length) {
-                    sourceDir = new File(args[++i]);
-                } else {
-                    System.err.println("Missing value for source directory");
-                    usage(args);
-                }
+                sourceDir = new File(getArg(args, ++i, "Missing value for source directory"));
+            } else if ("-t".equals(args[i])) {
+                testSuite = getArg(args, ++i, "Missing value for test suite");
             } else {
                 System.err.println("Unsupported flag: " + args[i]);
                 usage(args);
@@ -53,10 +51,25 @@
             usage(args);
         }
 
-        TestScanner scanner = new TestScanner(sourceDir);
+        if (testSuite == null) {
+            System.out.println("Test suite is required");
+            usage(args);
+        }
+
+        TestScanner scanner = new TestScanner(sourceDir, testSuite);
         List<String> testNames = scanner.getTestNames();
         for (String name : testNames) {
             System.out.println(name);
         }
     }
+
+    private static String getArg(String[] args, int index, String message) {
+        if (index < args.length) {
+            return args[index];
+        } else {
+            System.err.println(message);
+            usage(args);
+            return null;
+        }
+    }
 }
diff --git a/tools/cts-native-scanner/src/com/android/cts/nativescanner/TestScanner.java b/tools/cts-native-scanner/src/com/android/cts/nativescanner/TestScanner.java
index 8899111..9411566 100644
--- a/tools/cts-native-scanner/src/com/android/cts/nativescanner/TestScanner.java
+++ b/tools/cts-native-scanner/src/com/android/cts/nativescanner/TestScanner.java
@@ -43,8 +43,11 @@
     /** Directory to recursively scan for gTest test declarations. */
     private final File mSourceDir;
 
-    TestScanner(File sourceDir) {
+    private final String mTestSuite;
+
+    TestScanner(File sourceDir, String testSuite) {
         mSourceDir = sourceDir;
+        mTestSuite = testSuite;
     }
 
     public List<String> getTestNames() throws IOException {
@@ -90,13 +93,14 @@
                 String line = scanner.nextLine();
                 Matcher matcher = CLASS_REGEX.matcher(line);
                 if (matcher.matches()) {
-                    testNames.add("class:" + matcher.group(1));
+                    testNames.add("suite:" + mTestSuite);
+                    testNames.add("case:" + matcher.group(1));
                     continue;
                 }
 
                 matcher = METHOD_REGEX.matcher(line);
                 if (matcher.matches()) {
-                    testNames.add("method:" + matcher.group(1));
+                    testNames.add("test:" + matcher.group(1));
                     continue;
                 }
             }
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/CtsXmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/CtsXmlGenerator.java
index 5d5d8ff..ce4fdd7 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/CtsXmlGenerator.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/CtsXmlGenerator.java
@@ -15,6 +15,10 @@
  */
 package com.android.cts.xmlgenerator;
 
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
 import vogar.ExpectationStore;
 import vogar.ModeId;
 
@@ -23,16 +27,16 @@
 import java.util.HashSet;
 import java.util.Set;
 
-/**
- * Class that searches a source directory for native gTests and outputs a
- * test package xml.
- */
+import javax.xml.parsers.DocumentBuilderFactory;
+
+/** Class that outputs a test package xml. */
 public class CtsXmlGenerator {
 
     private static void usage(String[] args) {
         System.err.println("Arguments: " + Arrays.asList(args));
-        System.err.println("Usage: cts-native-xml-generator -p PACKAGE_NAME -n EXECUTABLE_NAME "
-                + " [-e EXPECTATION_FILE] [-o OUTPUT_FILE]");
+        System.err.println("Usage: cts-xml-generator -p PACKAGE_NAME -n NAME [-t TEST_TYPE]"
+                + " [-j JAR_PATH] [-i INSTRUMENTATION] [-m MANIFEST_FILE] [-e EXPECTATION_FILE]"
+                + " [-o OUTPUT_FILE]");
         System.exit(1);
     }
 
@@ -41,42 +45,50 @@
         String name = null;
         String outputPath = null;
         Set<File> expectationFiles = new HashSet<File>();
+        File manifestFile = null;
+        String instrumentation = null;
+        String testType = null;
+        String jarPath = null;
 
         for (int i = 0; i < args.length; i++) {
             if ("-p".equals(args[i])) {
-                if (i + 1 < args.length) {
-                    appPackageName = args[++i];
-                } else {
-                    System.err.println("Missing value for test package");
-                    usage(args);
-                }
+                appPackageName = getArg(args, ++i, "Missing value for test package");
             } else if ("-n".equals(args[i])) {
-                if (i + 1 < args.length) {
-                    name = args[++i];
-                } else {
-                    System.err.println("Missing value for executable name");
-                    usage(args);
-                }
+                name = getArg(args, ++i, "Missing value for executable name");
+            } else if ("-t".equals(args[i])) {
+                testType = getArg(args, ++i, "Missing value for test type");
+            } else if ("-j".equals(args[i])) {
+                jarPath = getArg(args, ++i, "Missing value for jar path");
+            } else if ("-m".equals(args[i])) {
+                manifestFile = new File(getArg(args, ++i, "Missing value for manifest"));
+            } else if ("-i".equals(args[i])) {
+                instrumentation = getArg(args, ++i, "Missing value for instrumentation");
             } else if ("-e".equals(args[i])) {
-                if (i + 1 < args.length) {
-                    expectationFiles.add(new File(args[++i]));
-                } else {
-                    System.err.println("Missing value for expectation store");
-                    usage(args);
-                }
+                expectationFiles.add(new File(getArg(args, ++i,
+                        "Missing value for expectation store")));
             } else if ("-o".equals(args[i])) {
-                if (i + 1 < args.length) {
-                    outputPath = args[++i];
-                } else {
-                    System.err.println("Missing value for output file");
-                    usage(args);
-                }
+                outputPath = getArg(args, ++i, "Missing value for output file");
             } else {
                 System.err.println("Unsupported flag: " + args[i]);
                 usage(args);
             }
         }
 
+        String appNameSpace = null;
+        String runner = null;
+        String targetNameSpace = null;
+
+        if (manifestFile != null) {
+            Document manifest = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+                    .parse(manifestFile);
+            Element documentElement = manifest.getDocumentElement();
+            appNameSpace = documentElement.getAttribute("package");
+            runner = getElementAttribute(documentElement, "instrumentation",
+                    "android:name");
+            targetNameSpace = getElementAttribute(documentElement, "instrumentation",
+                    "android:targetPackage");
+        }
+
         if (appPackageName == null) {
             System.out.println("Package name is required");
             usage(args);
@@ -86,7 +98,28 @@
         }
 
         ExpectationStore store = ExpectationStore.parse(expectationFiles, ModeId.DEVICE);
-        NativeXmlGenerator generator = new NativeXmlGenerator(store, appPackageName, name, outputPath);
+        XmlGenerator generator = new XmlGenerator(store, appNameSpace, appPackageName,
+                name, runner, instrumentation, targetNameSpace, jarPath, testType, outputPath);
         generator.writePackageXml();
     }
+
+    private static String getArg(String[] args, int index, String message) {
+        if (index < args.length) {
+            return args[index];
+        } else {
+            System.err.println(message);
+            usage(args);
+            return null;
+        }
+    }
+
+    private static String getElementAttribute(Element parentElement, String elementName,
+            String attributeName) {
+        NodeList nodeList = parentElement.getElementsByTagName(elementName);
+        if (nodeList.getLength() > 0) {
+             Element element = (Element) nodeList.item(0);
+             return element.getAttribute(attributeName);
+        }
+        return null;
+    }
 }
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/NativeXmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/NativeXmlGenerator.java
deleted file mode 100644
index 1692c10..0000000
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/NativeXmlGenerator.java
+++ /dev/null
@@ -1,156 +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.xmlgenerator;
-
-import vogar.Expectation;
-import vogar.ExpectationStore;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.util.Scanner;
-
-/**
- * Generator of TestPackage XML files for native tests.
- *
- * It takes in an input of the following form:
- *
- * class:TestClass1
- * method:testMethod1
- * method:testMethod2
- * class:TestClass2
- * method:testMethod1
- */
-class NativeXmlGenerator {
-
-    /** Test package name like "android.nativemedia" to group the tests. */
-    private final String mAppPackageName;
-
-    /** Name of the native executable. */
-    private final String mName;
-
-    /** Path to output file or null to just dump to standard out. */
-    private final String mOutputPath;
-
-    /** ExpectationStore to filter out known failures. */
-    private final ExpectationStore mExpectations;
-
-    NativeXmlGenerator(ExpectationStore expectations, String appPackageName, String name,
-            String outputPath) {
-        mAppPackageName = appPackageName;
-        mName = name;
-        mOutputPath = outputPath;
-        mExpectations = expectations;
-    }
-
-    public void writePackageXml() throws IOException {
-        OutputStream output = System.out;
-        if (mOutputPath != null) {
-            File outputFile = new File(mOutputPath);
-            output = new FileOutputStream(outputFile);
-        }
-
-        PrintWriter writer = null;
-        try {
-            writer = new PrintWriter(output);
-            writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
-            writeTestPackage(writer);
-        } finally {
-            if (writer != null) {
-                writer.close();
-            }
-        }
-    }
-
-    private void writeTestPackage(PrintWriter writer) {
-        writer.append("<TestPackage appPackageName=\"")
-                .append(mAppPackageName)
-                .append("\" name=\"")
-                .append(mName)
-                .println("\" testType=\"native\" version=\"1.0\">");
-        writeTestSuite(writer);
-        writer.println("</TestPackage>");
-    }
-
-    private void writeTestSuite(PrintWriter writer) {
-        /*
-         * Given "android.foo.bar.baz"...
-         *
-         * <TestSuite name="android">
-         *   <TestSuite name="foo">
-         *     <TestSuite name="bar">
-         *       <TestSuite name="baz">
-         */
-        Scanner scanner = null;
-        try {
-            scanner = new Scanner(mAppPackageName);
-            scanner.useDelimiter("\\.");
-
-            int numLevels = 0;
-            for (; scanner.hasNext(); numLevels++) {
-                String packagePart = scanner.next();
-                writer.append("<TestSuite name=\"").append(packagePart).println("\">");
-            }
-
-            writeTestCases(writer);
-
-            for (; numLevels > 0; numLevels--) {
-                writer.println("</TestSuite>");
-            }
-        } finally {
-            if (scanner != null) {
-                scanner.close();
-            }
-        }
-    }
-
-    private void writeTestCases(PrintWriter writer) {
-        String currentClassName = null;
-        Scanner scanner = new Scanner(System.in);
-        while (scanner.hasNextLine()) {
-            String line = scanner.nextLine();
-            String[] tokens = line.split(":");
-            if (tokens.length > 1) {
-                String type = tokens[0];
-                String value = tokens[1];
-                if ("class".equals(type)) {
-                    if (currentClassName != null) {
-                        writer.append("</TestCase>");
-                    }
-                    currentClassName = value;
-                    writer.append("<TestCase name=\"").append(value).println("\">");
-                } else if ("method".equals(type)) {
-                    String fullClassName = mAppPackageName + "." + currentClassName;
-                    if (!isKnownFailure(mExpectations, fullClassName, value)) {
-                        writer.append("<Test name=\"").append(value).println("\" />");
-                    }
-                }
-            }
-        }
-        if (currentClassName != null) {
-            writer.println("</TestCase>");
-        }
-    }
-
-    public static boolean isKnownFailure(ExpectationStore expectationStore,
-            String className, String methodName) {
-        String testName = String.format("%s#%s", className, methodName);
-        return expectationStore != null && expectationStore.get(testName) != Expectation.SUCCESS;
-    }
-}
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
new file mode 100644
index 0000000..bab3476
--- /dev/null
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
@@ -0,0 +1,44 @@
+/*
+ * 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.xmlgenerator;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+class TestCase {
+
+    private final String mName;
+
+    private final List<String> mTests = new ArrayList<String>();
+
+    public TestCase(String name) {
+        mName = name;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public void addTest(String test) {
+        mTests.add(test);
+    }
+
+    public Collection<String> getTests() {
+        return Collections.unmodifiableCollection(mTests);
+    }
+}
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestListParser.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestListParser.java
new file mode 100644
index 0000000..76e1437
--- /dev/null
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestListParser.java
@@ -0,0 +1,101 @@
+/*
+ * 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.xmlgenerator;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+/**
+ * Parser of test lists that are in the format of:
+ *
+ * suite:android.holo.cts
+ * case:HoloTest
+ * test:testHolo
+ * test:testHoloDialog
+ */
+class TestListParser {
+
+    public Collection<TestSuite> parse(InputStream input) {
+        Map<String, TestSuite> suiteMap = new HashMap<String, TestSuite>();
+        TestSuite currentSuite = null;
+        TestCase currentCase = null;
+        Scanner scanner = null;
+        try {
+            scanner = new Scanner(input);
+            while(scanner.hasNextLine()) {
+                String line = scanner.nextLine();
+                String[] tokens = line.split(":");
+                if (tokens.length != 2) {
+                    continue;
+                }
+
+                String key = tokens[0];
+                String value = tokens[1];
+                if ("suite".equals(key)) {
+                    currentSuite = handleSuite(suiteMap, value);
+                } else if ("case".equals(key)) {
+                    currentCase = handleCase(currentSuite, value);
+                } else if ("test".equals(key)) {
+                    handleTest(currentCase, value);
+                }
+            }
+        } finally {
+            if (scanner != null) {
+                scanner.close();
+            }
+        }
+        return suiteMap.values();
+    }
+
+    private TestSuite handleSuite(Map<String, TestSuite> suiteMap, String fullSuite) {
+        String[] suites = fullSuite.split("\\.");
+        int numSuites = suites.length;
+        TestSuite lastSuite = null;
+
+        for (int i = 0; i < numSuites; i++) {
+            String name = suites[i];
+            if (lastSuite != null) {
+                if (lastSuite.hasSuite(name)) {
+                    lastSuite = lastSuite.getSuite(name);
+                } else {
+                    TestSuite newSuite = new TestSuite(name);
+                    lastSuite.addSuite(newSuite);
+                    lastSuite = newSuite;
+                }
+            } else if (suiteMap.containsKey(name)) {
+                lastSuite = suiteMap.get(name);
+            } else {
+                lastSuite = new TestSuite(name);
+                suiteMap.put(name, lastSuite);
+            }
+        }
+
+        return lastSuite;
+    }
+
+    private TestCase handleCase(TestSuite suite, String caseName) {
+        TestCase testCase = new TestCase(caseName);
+        suite.addCase(testCase);
+        return testCase;
+    }
+
+    private void handleTest(TestCase testCase, String test) {
+        testCase.addTest(test);
+    }
+}
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
new file mode 100644
index 0000000..3c29603
--- /dev/null
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
@@ -0,0 +1,64 @@
+/*
+ * 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.xmlgenerator;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class TestSuite {
+
+    private final String mName;
+
+    private final Map<String, TestSuite> mSuites = new HashMap<String, TestSuite>();
+
+    private final List<TestCase> mCases = new ArrayList<TestCase>();
+
+    public TestSuite(String name) {
+        mName = name;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public boolean hasSuite(String name) {
+        return mSuites.containsKey(name);
+    }
+
+    public TestSuite getSuite(String name) {
+        return mSuites.get(name);
+    }
+
+    public void addSuite(TestSuite suite) {
+        mSuites.put(suite.mName, suite);
+    }
+
+    public Collection<TestSuite> getSuites() {
+        return Collections.unmodifiableCollection(mSuites.values());
+    }
+
+    public void addCase(TestCase testCase) {
+        mCases.add(testCase);
+    }
+
+    public Collection<TestCase> getCases() {
+        return Collections.unmodifiableCollection(mCases);
+    }
+}
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
new file mode 100644
index 0000000..9951b8d
--- /dev/null
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
@@ -0,0 +1,192 @@
+/*
+ * 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.xmlgenerator;
+
+import vogar.Expectation;
+import vogar.ExpectationStore;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Collection;
+
+/**
+ * Generator of TestPackage XML files for native tests.
+ *
+ * It takes in an input of the following form:
+ *
+ * suite: x.y.z
+ * case:TestClass1
+ * test:testMethod1
+ * test:testMethod2
+ * case:TestClass2
+ * test:testMethod1
+ * suite: x.y
+ * case:TestClass3
+ * test:testMethod2
+ */
+class XmlGenerator {
+
+    /** Example: com.android.cts.holo */
+    private final String mAppNamespace;
+
+    /** Test package name like "android.nativemedia" to group the tests. */
+    private final String mAppPackageName;
+
+    /** Name of the native executable. */
+    private final String mName;
+
+    /** Test runner */
+    private final String mRunner;
+
+    private final String mTargetBinaryName;
+
+    private final String mTargetNameSpace;
+
+    private final String mJarPath;
+
+    private final String mTestType;
+
+    /** Path to output file or null to just dump to standard out. */
+    private final String mOutputPath;
+
+    /** ExpectationStore to filter out known failures. */
+    private final ExpectationStore mExpectations;
+
+    XmlGenerator(ExpectationStore expectations, String appNameSpace, String appPackageName,
+            String name, String runner, String targetBinaryName, String targetNameSpace,
+            String jarPath, String testType, String outputPath) {
+        mAppNamespace = appNameSpace;
+        mAppPackageName = appPackageName;
+        mName = name;
+        mRunner = runner;
+        mTargetBinaryName = targetBinaryName;
+        mTargetNameSpace = targetNameSpace;
+        mJarPath = jarPath;
+        mTestType = testType;
+        mOutputPath = outputPath;
+        mExpectations = expectations;
+    }
+
+    public void writePackageXml() throws IOException {
+        OutputStream output = System.out;
+        if (mOutputPath != null) {
+            File outputFile = new File(mOutputPath);
+            output = new FileOutputStream(outputFile);
+        }
+
+        PrintWriter writer = null;
+        try {
+            writer = new PrintWriter(output);
+            writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+            writeTestPackage(writer);
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    private void writeTestPackage(PrintWriter writer) {
+        writer.append("<TestPackage");
+        if (mAppNamespace != null) {
+            writer.append(" appNameSpace=\"").append(mAppNamespace).append("\"");
+        }
+
+        writer.append(" appPackageName=\"").append(mAppPackageName).append("\"");
+        writer.append(" name=\"").append(mName).append("\"");
+
+        if (mRunner != null) {
+            writer.append(" runner=\"").append(mRunner).append("\"");
+        }
+
+        if (mAppNamespace != null && mTargetNameSpace != null
+                && !mAppNamespace.equals(mTargetNameSpace)) {
+            writer.append(" targetBinaryName=\"").append(mTargetBinaryName).append("\"");
+            writer.append(" targetNameSpace=\"").append(mTargetNameSpace).append("\"");
+        }
+
+        if (mTestType != null) {
+            writer.append(" testType=\"").append(mTestType).append("\"");
+        }
+
+        if (mJarPath != null) {
+            writer.append(" jarPath=\"").append(mJarPath).append("\"");
+        }
+
+        writer.println(" version=\"1.0\">");
+
+        TestListParser parser = new TestListParser();
+        Collection<TestSuite> suites = parser.parse(System.in);
+        StringBuilder nameCollector = new StringBuilder();
+        writeTestSuites(writer, suites, nameCollector);
+        writer.println("</TestPackage>");
+    }
+
+    private void writeTestSuites(PrintWriter writer, Collection<TestSuite> suites,
+            StringBuilder nameCollector) {
+        for (TestSuite suite : suites) {
+            writer.append("<TestSuite name=\"").append(suite.getName()).println("\">");
+
+            String namePart = suite.getName();
+            if (nameCollector.length() > 0) {
+                namePart = "." + namePart;
+            }
+            nameCollector.append(namePart);
+
+            writeTestSuites(writer, suite.getSuites(), nameCollector);
+            writeTestCases(writer, suite.getCases(), nameCollector);
+
+            nameCollector.delete(nameCollector.length() - namePart.length(),
+                    nameCollector.length());
+            writer.println("</TestSuite>");
+        }
+    }
+
+    private void writeTestCases(PrintWriter writer, Collection<TestCase> cases,
+            StringBuilder nameCollector) {
+        for (TestCase testCase : cases) {
+            String name = testCase.getName();
+            writer.append("<TestCase name=\"").append(name).println("\">");
+            nameCollector.append('.').append(name);
+
+            writeTests(writer, testCase.getTests(), nameCollector);
+
+            nameCollector.delete(nameCollector.length() - name.length() - 1,
+                    nameCollector.length());
+            writer.println("</TestCase>");
+        }
+    }
+
+    private void writeTests(PrintWriter writer, Collection<String> tests,
+            StringBuilder nameCollector) {
+        for (String test : tests) {
+            nameCollector.append('#').append(test);
+            if (!isKnownFailure(mExpectations, nameCollector.toString())) {
+                writer.append("<Test name=\"").append(test).println("\" />");
+            }
+            nameCollector.delete(nameCollector.length() - test.length() - 1,
+                    nameCollector.length());
+        }
+    }
+
+    public static boolean isKnownFailure(ExpectationStore expectationStore, String testName) {
+        return expectationStore != null && expectationStore.get(testName) != Expectation.SUCCESS;
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 855c209..686c90a 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -84,6 +84,9 @@
     @Option(name = "quiet-output", description = "Mute display of test results.")
     private boolean mQuietOutput = false;
 
+    @Option(name = "result-server", description = "Server to publish test results.")
+    private String mResultServer;
+
     protected IBuildInfo mBuildInfo;
     private String mStartTime;
     private String mDeviceSerial;
@@ -254,9 +257,18 @@
             CLog.w("Unable to create XML report");
             return;
         }
-        createXmlResult(mReportDir, mStartTime, elapsedTime);
+
+        File reportFile = getResultFile(mReportDir);
+        createXmlResult(reportFile, mStartTime, elapsedTime);
         copyFormattingFiles(mReportDir);
         zipResults(mReportDir);
+
+        try {
+            ResultReporter reporter = new ResultReporter(mResultServer, reportFile);
+            reporter.reportResult();
+        } catch (IOException e) {
+            CLog.e(e);
+        }
     }
 
     private void logResult(String format, Object... args) {
@@ -281,12 +293,11 @@
     /**
      * Creates a report file and populates it with the report data from the completed tests.
      */
-    private void createXmlResult(File reportDir, String startTimestamp, long elapsedTime) {
+    private void createXmlResult(File reportFile, String startTimestamp, long elapsedTime) {
         String endTime = getTimestamp();
-
         OutputStream stream = null;
         try {
-            stream = createOutputResultStream(reportDir);
+            stream = createOutputResultStream(reportFile);
             KXmlSerializer serializer = new KXmlSerializer();
             serializer.setOutput(stream, "UTF-8");
             serializer.startDocument("UTF-8", false);
@@ -331,11 +342,14 @@
         //serializer.endTag(ns, RESULT_TAG);
     }
 
+    private File getResultFile(File reportDir) {
+        return new File(reportDir, TEST_RESULT_FILE_NAME);
+    }
+
     /**
      * Creates the output stream to use for test results. Exposed for mocking.
      */
-    OutputStream createOutputResultStream(File reportDir) throws IOException {
-        File reportFile = new File(reportDir, TEST_RESULT_FILE_NAME);
+    OutputStream createOutputResultStream(File reportFile) throws IOException {
         logResult("Created xml report file at file://%s", reportFile.getAbsolutePath());
         return new FileOutputStream(reportFile);
     }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
index 8ee9c0f..9d903dd 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
@@ -28,11 +28,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.net.HttpURLConnection;
-import java.net.URL;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
@@ -46,7 +41,6 @@
  */
 public class IssueReporter implements ITestInvocationListener {
 
-    private static final String FORM_DATA_BOUNDARY = "C75I55u3R3p0r73r";
     private static final int BUGREPORT_SIZE = 500 * 1024;
 
     private static final String PRODUCT_NAME_KEY = "buildName";
@@ -87,22 +81,42 @@
      */
     private void setBugReport(InputStreamSource dataStream) throws IOException {
         if (mCurrentIssue != null) {
-            InputStream input = dataStream.createInputStream();
-            ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(BUGREPORT_SIZE);
-            GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
-            for (byte[] buffer = new byte[1024]; input.read(buffer) >= 0; ) {
-                gzipOutput.write(buffer);
-            }
-            gzipOutput.close();
-
             // Only one bug report can be stored at a time and they are gzipped to
             // about 0.5 MB so there shoudn't be any memory leak bringing down CTS.
-            mCurrentIssue.mBugReport = byteOutput.toByteArray();
+            InputStream input = null;
+            try {
+                input = dataStream.createInputStream();
+                mCurrentIssue.mBugReport = getBytes(input, BUGREPORT_SIZE);
+            } finally {
+                if (input != null) {
+                    input.close();
+                }
+            }
         } else {
             CLog.e("setBugReport is getting called on an empty issue...");
         }
     }
 
+    /**
+     * @param input that will be gzipped and returne as a byte array
+     * @param size of the output expected
+     * @return the byte array with the input's data
+     * @throws IOException
+     */
+    static byte[] getBytes(InputStream input, int size) throws IOException {
+        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(size);
+        GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
+        for (byte[] buffer = new byte[1024]; ; ) {
+            int numRead = input.read(buffer);
+            if (numRead < 0) {
+                break;
+            }
+            gzipOutput.write(buffer, 0, numRead);
+        }
+        gzipOutput.close();
+        return byteOutput.toByteArray();
+    }
+
     @Override
     public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
         if (mCurrentIssue != null) {
@@ -158,32 +172,14 @@
                 return null;
             }
 
-            HttpURLConnection connection = null;
-
-            try {
-                URL url = new URL(mServerUrl);
-                connection = (HttpURLConnection) url.openConnection();
-                connection.setRequestMethod("POST");
-                connection.setDoOutput(true);
-                connection.setRequestProperty("Content-Type",
-                        "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
-
-                byte[] body = getContentBody();
-                connection.setRequestProperty("Content-Length", Integer.toString(body.length));
-
-                OutputStream output = connection.getOutputStream();
-                output.write(body);
-                output.close();
-
-                // Open the stream to get a response. Otherwise request will be cancelled.
-                InputStream input = connection.getInputStream();
-                input.close();
-
-            } finally {
-                if (connection != null) {
-                    connection.disconnect();
-                }
-            }
+            new MultipartForm(mServerUrl)
+                    .addFormValue("productName", mProductName)
+                    .addFormValue("buildType", mBuildType)
+                    .addFormValue("buildId", mBuildId)
+                    .addFormValue("testName", mTestName)
+                    .addFormValue("stackTrace", mStackTrace)
+                    .addFormFile("bugReport", "bugreport.txt.gz", mBugReport)
+                    .submit();
 
             return null;
         }
@@ -191,43 +187,6 @@
         private boolean isEmpty(String value) {
             return value == null || value.trim().isEmpty();
         }
-
-        private byte[] getContentBody() throws IOException {
-            ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
-            PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOutput));
-            writer.println();
-            writeFormField(writer, "productName", mProductName);
-            writeFormField(writer, "buildType", mBuildType);
-            writeFormField(writer, "buildId", mBuildId);
-            writeFormField(writer, "testName", mTestName);
-            writeFormField(writer, "stackTrace", mStackTrace);
-            if (mBugReport != null) {
-                writeFormFileHeader(writer, "bugReport", "bugReport.txt.gz");
-                writer.flush(); // Must flush here before writing to the byte stream!
-                byteOutput.write(mBugReport);
-                writer.println();
-            }
-            writer.append("--").append(FORM_DATA_BOUNDARY).println("--");
-            writer.flush();
-            writer.close();
-            return byteOutput.toByteArray();
-        }
-
-        private void writeFormField(PrintWriter writer, String name, String value) {
-            writer.append("--").println(FORM_DATA_BOUNDARY);
-            writer.append("Content-Disposition: form-data; name=\"").append(name).println("\"");
-            writer.println();
-            writer.println(value);
-        }
-
-        private void writeFormFileHeader(PrintWriter writer, String name, String fileName) {
-            writer.append("--").println(FORM_DATA_BOUNDARY);
-            writer.append("Content-Disposition: form-data; name=\"").append(name);
-            writer.append("\"; filename=\"").append(fileName).println("\"");
-            writer.println("Content-Type: application/x-gzip");
-            writer.println("Content-Transfer-Encoding: binary");
-            writer.println();
-        }
     }
 
     @Override
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java
new file mode 100644
index 0000000..f3ef0bb
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java
@@ -0,0 +1,144 @@
+/*
+ * 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.tradefed.result;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/** MultipartForm builds a multipart form and submits it. */
+class MultipartForm {
+
+    private static final String FORM_DATA_BOUNDARY = "C75I55u3R3p0r73r";
+
+    private final String mServerUrl;
+
+    private final Map<String, String> mFormValues = new HashMap<String, String>();
+
+    private String mName;
+    private String mFileName;
+    private byte[] mData;
+
+    public MultipartForm(String serverUrl) {
+        mServerUrl = serverUrl;
+    }
+
+    public MultipartForm addFormValue(String name, String value) {
+        mFormValues.put(name, value);
+        return this;
+    }
+
+    public MultipartForm addFormFile(String name, String fileName, byte[] data) {
+        mName = name;
+        mFileName = fileName;
+        mData = data;
+        return this;
+    }
+
+    public void submit() throws IOException {
+        String redirectUrl = submitForm(mServerUrl);
+        if (redirectUrl != null) {
+            submitForm(redirectUrl);
+        }
+    }
+
+    /**
+     * @param serverUrl to post the data to
+     * @return a url if the server redirected to another url
+     * @throws IOException
+     */
+    private String submitForm(String serverUrl) throws IOException {
+        HttpURLConnection connection = null;
+        try {
+            URL url = new URL(serverUrl);
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setInstanceFollowRedirects(false);
+            connection.setRequestMethod("POST");
+            connection.setDoOutput(true);
+            connection.setRequestProperty("Content-Type",
+                    "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
+
+            byte[] body = getContentBody();
+            connection.setRequestProperty("Content-Length", Integer.toString(body.length));
+
+            OutputStream output = connection.getOutputStream();
+            try {
+                output.write(body);
+            } finally {
+                output.close();
+            }
+
+            // Open the stream to get a response. Otherwise request will be cancelled.
+            InputStream input = connection.getInputStream();
+            input.close();
+
+            if (connection.getResponseCode() == 302) {
+                return connection.getHeaderField("Location");
+            }
+        } finally {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+
+        return null;
+    }
+
+    private byte[] getContentBody() throws IOException {
+        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
+        PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOutput));
+        writer.println();
+
+        for (Map.Entry<String, String> formValue : mFormValues.entrySet()) {
+            writeFormField(writer, formValue.getKey(), formValue.getValue());
+        }
+
+        if (mData != null) {
+            writeFormFileHeader(writer, mName, mFileName);
+            writer.flush(); // Must flush here before writing to the byte stream!
+            byteOutput.write(mData);
+            writer.println();
+        }
+        writer.append("--").append(FORM_DATA_BOUNDARY).println("--");
+        writer.flush();
+        writer.close();
+        return byteOutput.toByteArray();
+    }
+
+    private void writeFormField(PrintWriter writer, String name, String value) {
+        writer.append("--").println(FORM_DATA_BOUNDARY);
+        writer.append("Content-Disposition: form-data; name=\"").append(name).println("\"");
+        writer.println();
+        writer.println(value);
+    }
+
+    private void writeFormFileHeader(PrintWriter writer, String name, String fileName) {
+        writer.append("--").println(FORM_DATA_BOUNDARY);
+        writer.append("Content-Disposition: form-data; name=\"").append(name);
+        writer.append("\"; filename=\"").append(fileName).println("\"");
+        writer.println("Content-Type: application/x-gzip");
+        writer.println("Content-Transfer-Encoding: binary");
+        writer.println();
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java
new file mode 100644
index 0000000..05192c9
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.tradefed.result;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Class that sends a HTTP POST multipart/form-data request containing
+ * the test result XML.
+ */
+class ResultReporter {
+
+    private static final int RESULT_XML_BYTES = 500 * 1024;
+
+    private final String mServerUrl;
+
+    private final File mReportFile;
+
+    ResultReporter(String serverUrl, File reportFile) {
+        mServerUrl = serverUrl;
+        mReportFile = reportFile;
+    }
+
+    public void reportResult() throws IOException {
+        if (isEmpty(mServerUrl)) {
+            return;
+        }
+
+        InputStream input = new FileInputStream(mReportFile);
+        try {
+            byte[] data = IssueReporter.getBytes(input, RESULT_XML_BYTES);
+            new MultipartForm(mServerUrl)
+                    .addFormFile("resultXml", "testResult.xml.gz", data)
+                    .submit();
+        } finally {
+            input.close();
+        }
+    }
+
+    private boolean isEmpty(String value) {
+        return value == null || value.trim().isEmpty();
+    }
+}
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 8cccab0..4067e0a 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
@@ -48,7 +48,6 @@
     private String mAppNameSpace = null;
     private String mName = null;
     private String mRunner = null;
-    private boolean mIsHostSideTest = false;
     private boolean mIsVMHostTest = false;
     private String mTestType = null;
     private String mJarPath = null;
@@ -112,15 +111,6 @@
         return mRunner;
     }
 
-    void setIsHostSideTest(boolean hostSideTest) {
-        mIsHostSideTest = hostSideTest;
-
-    }
-
-    boolean isHostSideTest() {
-        return mIsHostSideTest;
-    }
-
     void setIsVMHostTest(boolean vmHostTest) {
         mIsVMHostTest = vmHostTest;
 
@@ -219,7 +209,7 @@
         mExcludedTestFilter.setTestInclusion(mClassName, mMethodName);
         mTests = filterTests();
 
-        if (mIsHostSideTest) {
+        if ("hostSideOnly".equals(mTestType)) {
             CLog.d("Creating host test for %s", mName);
             JarHostTest hostTest = new JarHostTest();
             hostTest.setRunName(getUri());
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 f1b6ed0..c8e0def 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
@@ -66,7 +66,6 @@
                 final String testPackageNameSpace = attributes.getValue("appNameSpace");
                 final String packageName = attributes.getValue("name");
                 final String runnerName = attributes.getValue("runner");
-                final String hostSideTest = attributes.getValue("hostSideOnly");
                 final String vmHostTest = attributes.getValue("vmHostTest");
                 final String testType = attributes.getValue("testType");
                 final String jarPath = attributes.getValue("jarPath");
@@ -83,7 +82,6 @@
                 mPackageDef.setAppNameSpace(testPackageNameSpace);
                 mPackageDef.setName(packageName);
                 mPackageDef.setRunner(runnerName);
-                mPackageDef.setIsHostSideTest(parseBoolean(hostSideTest));
                 mPackageDef.setIsVMHostTest(parseBoolean(vmHostTest));
                 mPackageDef.setTestType(testType);
                 mPackageDef.setJarPath(jarPath);
diff --git a/tools/tradefed-host/tests/run_unit_tests.sh b/tools/tradefed-host/tests/run_unit_tests.sh
new file mode 100755
index 0000000..fc19a02
--- /dev/null
+++ b/tools/tradefed-host/tests/run_unit_tests.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# 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.
+
+# helper script for running the cts-tradefed unit tests
+
+checkFile() {
+    if [ ! -f "$1" ]; then
+        echo "Unable to locate $1"
+        exit
+    fi;
+}
+
+# check if in Android build env
+if [ ! -z ${ANDROID_BUILD_TOP} ]; then
+    HOST=`uname`
+    if [ "$HOST" == "Linux" ]; then
+        OS="linux-x86"
+    elif [ "$HOST" == "Darwin" ]; then
+        OS="darwin-x86"
+    else
+        echo "Unrecognized OS"
+        exit
+    fi;
+fi;
+
+JAR_DIR=${ANDROID_BUILD_TOP}/out/host/$OS/framework
+JARS="ddmlib-prebuilt.jar tradefed-prebuilt.jar hosttestlib.jar cts-tradefed.jar cts-tradefed-tests.jar"
+
+for JAR in $JARS; do
+    checkFile ${JAR_DIR}/${JAR}
+    JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}
+done
+
+java $RDBG_FLAG \
+  -cp ${JAR_PATH} com.android.tradefed.command.Console run singleCommand host -n --class com.android.cts.tradefed.UnitTests "$@"
+
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 b24c0e3..482844c 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
@@ -79,7 +79,7 @@
         TestPackageXmlParser parser = new TestPackageXmlParser();
         parser.parse(getStringAsStream(HOST_TEST_DATA));
         TestPackageDef def = parser.getTestPackageDef();
-        assertTrue(def.isHostSideTest());
+        // assertTrue(def.isHostSideTest());
         assertEquals(3, def.getTests().size());
         Iterator<TestIdentifier> iterator = def.getTests().iterator();
 
@@ -103,7 +103,7 @@
         TestPackageXmlParser parser = new TestPackageXmlParser();
         parser.parse(getStringAsStream(BAD_HOST_TEST_DATA));
         TestPackageDef def = parser.getTestPackageDef();
-        assertFalse(def.isHostSideTest());
+        // assertFalse(def.isHostSideTest());
     }
 
     /**
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 9eb26af..d5ca8ab 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -74,20 +74,14 @@
 
   def GenerateTestDescriptions(self):
     """Generate test descriptions for all packages."""
-    pool = Pool(processes=16)
+    pool = Pool(processes=2)
 
     # individually generate descriptions not following conventions
     pool.apply_async(GenerateSignatureCheckDescription, [self.test_repository])
     pool.apply_async(GenerateReferenceAppDescription, [self.test_repository])
-    pool.apply_async(GenerateAppSecurityDescription, [self.temp_dir,
-        self.test_repository, self.android_root, self.doclet_path])
 
     # generate test descriptions for android tests
     results = []
-    android_packages = GetSubDirectories(self.test_root)
-    for package in android_packages:
-      results.append(pool.apply_async(GenerateTestDescription, [self.test_root, self.temp_dir,
-          self.test_repository, self.android_root, self.doclet_path, package]))
     pool.close()
     pool.join()
     return sum(map(lambda result: result.get(), results))
@@ -165,153 +159,6 @@
   package.WriteDescription(description)
   description.close()
 
-def GenerateAppSecurityDescription(temp_dir, test_repository, android_root, doclet_path):
-  """Generate the test description for the application security tests."""
-  test_root = 'cts/tests/appsecurity-tests'
-  makefile_name = os.path.join(test_root, 'Android.mk')
-  makefile_vars = GetMakeFileVars(makefile_name)
-  name = makefile_vars['LOCAL_MODULE']
-  package_name = 'android.tests.appsecurity'
-  LogGenerateDescription(package_name)
-  temp_desc = os.path.join(temp_dir, 'description.xml')
-  RunDescriptionGeneratorDoclet(android_root, doclet_path,
-      os.path.join(test_root, 'src'), temp_desc)
-  doc = dom.parse(temp_desc)
-  test_description = doc.getElementsByTagName('TestPackage')[0]
-  test_description.setAttribute('name', package_name)
-  test_description.setAttribute('appPackageName', package_name)
-  test_description.setAttribute('hostSideOnly', 'true')
-  test_description.setAttribute('jarPath', name + '.jar')
-  description = open(os.path.join(test_repository, package_name + '.xml'), 'w')
-  doc.writexml(description, addindent='    ', encoding='UTF-8')
-  description.close()
-
-
-def GenerateTestDescription(test_root, temp_dir, test_repository, android_root,
-                            doclet_path, package):
-
-  app_package_name = 'android.' + package
-  package_root = os.path.join(test_root, package)
-
-  makefile_name = os.path.join(package_root, 'Android.mk')
-  if not os.path.exists(makefile_name):
-    print 'Skipping directory "%s" due to missing Android.mk' % package_root
-    return 0
-  makefile_vars = GetMakeFileVars(makefile_name)
-
-  manifest_name = os.path.join(package_root, 'AndroidManifest.xml')
-  if not os.path.exists(manifest_name):
-    print 'Skipping directory "%s" due to missing AndroidManifest.xml' % package_root
-    return 0
-  manifest = tools.XmlFile(manifest_name)
-
-  LogGenerateDescription(app_package_name)
-
-  # Run the description generator doclet to get the test package structure
-  # TODO: The Doclet does not currently add all required attributes. Instead of rewriting
-  # the document below, additional attributes should be passed to the Doclet as arguments.
-  temp_desc = os.path.join(temp_dir, app_package_name + '-description.xml')
-
-  returncode = RunDescriptionGeneratorDoclet(android_root, doclet_path, package_root, temp_desc)
-  if returncode != 0:
-    print 'Error occurred while running description generator...'
-    return 1
-
-  # obtain missing attribute values from the makefile and manifest
-  package_name = makefile_vars['LOCAL_PACKAGE_NAME']
-  runner = manifest.GetAndroidAttr('instrumentation', 'name')
-  target_package = manifest.GetAndroidAttr('instrumentation', 'targetPackage')
-  target_binary_name = makefile_vars.get('LOCAL_INSTRUMENTATION_FOR')
-
-  # add them to the document
-  doc = dom.parse(temp_desc)
-  test_description = doc.getElementsByTagName('TestPackage')[0]
-  test_description.setAttribute('name', package_name)
-  test_description.setAttribute('runner', runner)
-  test_package = manifest.GetAttr('manifest', 'package')
-  test_description.setAttribute('appNameSpace', test_package)
-  test_description.setAttribute('appPackageName', app_package_name)
-  if not test_package == target_package:
-    test_description.setAttribute('targetNameSpace', target_package)
-    test_description.setAttribute('targetBinaryName', target_binary_name)
-  description = open(os.path.join(test_repository, package_name + '.xml'), 'w')
-  doc.writexml(description, addindent='    ', encoding='UTF-8')
-  description.close()
-  return 0
-
-def RunDescriptionGeneratorDoclet(android_root, doclet_path, source_root, output_file):
-  """Generate a test package description by running the DescriptionGenerator doclet.
-
-  Args:
-    android_root: Root directory of the Android source tree.
-    doclet_path: Class path where the DescriptionGenerator doclet can be found.
-    source_root: Directory under which tests should be searched.
-    output_file: Name of the file where the description gets written.
-
-  Returns:
-    The exit code of the DescriptionGenerator doclet run.
-  """
-  # Make sure sourceRoot is relative to  self.android_root
-  source_root = RelPath(source_root, android_root)
-
-  # To determine whether a class is a JUnit test, the Doclet needs to have all intermediate
-  # subclasses of TestCase as well as the JUnit framework itself on the source path.
-  # Annotation classes are also required, since test annotations go into the description.
-  sourcepath = [
-      'frameworks/base/core/java',            # android test classes
-      'frameworks/base/test-runner/src',      # test runner
-      'libcore/junit/src/main/java',          # junit classes
-      'development/tools/hosttestlib/src',    # hosttestlib TestCase extensions
-      'libcore/dalvik/src/main/java',         # test annotations
-      'cts/tests/src',                        # cts test stubs
-      source_root                             # the source for this package
-  ]
-  sourcepath = [os.path.join(android_root, x) for x in sourcepath]
-  classpath = [
-      'prebuilt/common/tradefed/tradefed-prebuilt.jar',
-  ]
-  classpath = [os.path.join(android_root, x) for x in classpath]
-  cmd = ('javadoc -o %s -J-Xmx512m -quiet -doclet DescriptionGenerator -docletpath %s'
-         ' -sourcepath %s -classpath %s ') % (output_file, doclet_path, ':'.join(sourcepath),
-         ':'.join(classpath))
-  sources = []
-
-  def AddFile(sources, folder, names):
-    """Find *.java."""
-    sources.extend([os.path.join(folder, name) for name in names if name.endswith('.java')])
-
-  os.path.walk(os.path.join(android_root, source_root), AddFile, sources)
-  cmd += ' '.join(sources)
-  proc = subprocess.Popen(cmd, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
-  # read and discard any output
-  (outdata, errdata) = proc.communicate()
-  if proc.returncode != 0:
-    print '%s\n%s' % (outdata, errdata)
-  # wait for process to terminate and return exit value
-  return proc.wait()
-
-def RelPath(path, start=os.getcwd()):
-  """Get a relative version of a path.
-
-  This is equivalent to os.path.relpath, which is only available since Python 2.6.
-
-  Args:
-    path: The path to transform.
-    start: The base path. Defaults to the current working directory.
-
-  Returns:
-    A transformed path that is relative to start.
-  """
-  path_dirs = os.path.abspath(path).split(os.path.sep)
-  start_dirs = os.path.abspath(start).split(os.path.sep)
-
-  num_common = len(os.path.commonprefix([start_dirs, path_dirs]))
-
-  result_dirs = ['..'] * (len(start_dirs) - num_common) + path_dirs[num_common:]
-  if result_dirs:
-    return os.path.join(*result_dirs)
-  return start
-
 if __name__ == '__main__':
   builder = CtsBuilder(sys.argv)
   result = builder.GenerateTestDescriptions()