Merge "Updated CTS tests due to API change - touch exploration."
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 24e9fdc..e104d82 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -69,32 +69,23 @@
             <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
         </activity>
 
-        <activity android:name=".sensors.MagnetometerTestActivity" android:label="@string/snsr_mag_test"
-                android:screenOrientation="nosensor">
+        <activity android:name=".audioquality.AudioQualityVerifierActivity"
+                android:label="@string/aq_verifier">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
         </activity>
 
-      <activity android:name=".audioquality.AudioQualityVerifierActivity"
-              android:label="@string/aq_verifier">
-          <intent-filter>
-              <action android:name="android.intent.action.MAIN" />
-              <category android:name="android.cts.intent.category.MANUAL_TEST" />
-          </intent-filter>
-          <meta-data android:name="test_category" android:value="@string/test_category_audio" />
-      </activity>
-      
-      <activity android:name=".audioquality.CalibrateVolumeActivity"
-                android:label="@string/aq_calibrate_volume_name" />
-      
-      <activity android:name=".audioquality.ViewResultsActivity"
-                android:label="@string/aq_view_results_name" />
+        <activity android:name=".audioquality.CalibrateVolumeActivity"
+                  android:label="@string/aq_calibrate_volume_name" />
 
-      <service android:name=".audioquality.ExperimentService" />
-      
+        <activity android:name=".audioquality.ViewResultsActivity"
+                  android:label="@string/aq_view_results_name" />
+
+        <service android:name=".audioquality.ExperimentService" />
+
    </application>
 
 </manifest> 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagnetometerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagnetometerTestActivity.java
deleted file mode 100644
index f3ba411..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagnetometerTestActivity.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.sensors;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.opengl.GLSurfaceView;
-import android.os.Bundle;
-
-/**
- * CTS Verifier case for verifying correct integration of accelerometer.
- * Displays a wedge using OpenGL that, on a correctly-integrated device, always
- * points down.
- */
-public class MagnetometerTestActivity extends PassFailButtons.Activity {
-    private GLSurfaceView mGLSurfaceView;
-
-    private AccelerometerTestRenderer mListener;
-
-    private SensorManager mSensorManager;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mSensorManager = (SensorManager) getApplicationContext().getSystemService(
-                Context.SENSOR_SERVICE);
-        AccelerometerTestRenderer renderer = new MagnetometerTestRenderer(this);
-        mListener = renderer;
-
-        setContentView(R.layout.pass_fail_gl);
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.snsr_mag_test, R.string.snsr_mag_test_info, -1);
-        mGLSurfaceView = (GLSurfaceView) findViewById(R.id.gl_surface_view);
-        mGLSurfaceView.setRenderer(renderer);
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mSensorManager.unregisterListener(mListener);
-        mGLSurfaceView.onPause();
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mSensorManager.registerListener(mListener, mSensorManager.getSensorList(
-                Sensor.TYPE_MAGNETIC_FIELD).get(0), SensorManager.SENSOR_DELAY_UI);
-        mGLSurfaceView.onResume();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagnetometerTestRenderer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagnetometerTestRenderer.java
deleted file mode 100644
index b5d4587..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagnetometerTestRenderer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.sensors;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-
-public class MagnetometerTestRenderer extends AccelerometerTestRenderer {
-    public MagnetometerTestRenderer(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void onSensorChanged(SensorEvent event) {
-        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
-            /*
-             * The base class is written for accelerometer, where the vector
-             * points *away* from the thing being measured (i.e. gravity). But
-             * our vector points *toward* the thing being measured (i.e.
-             * magnetic north pole). Accordingly, the base class has an
-             * inversion to handle that that doesn't apply to us, so the
-             * simplest method is just to flip our vector to point in the exact
-             * opposite direction and then everything works out in the base
-             * class.
-             */
-            event.values[0] *= -1;
-            event.values[1] *= -1;
-            event.values[2] *= -1;
-
-            // rest of method is the same as in base class
-            normalize(event.values);
-            event.values[1] *= -1;
-            crossProduct(event.values, Z_AXIS, mCrossProd);
-            mAngle = (float) Math.acos(dotProduct(event.values, Z_AXIS));
-        }
-    }
-}
diff --git a/tests/assets/webkit/form_page.html b/tests/assets/webkit/form_page.html
new file mode 100644
index 0000000..b7a32a3
--- /dev/null
+++ b/tests/assets/webkit/form_page.html
@@ -0,0 +1,41 @@
+<!-- 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.
+-->
+
+<html>
+<head>
+    <title>Test Page</title>
+</head>
+<body>
+  <a name="text" />
+  <a id=someTextId>Some text&nbsp;</a>
+  <a id=nestedLinkId>Is not nested, and is not unique!</a>
+  <div id=divId>A div
+    <a id=nestedLinkId>Nested text</a>
+  </div>
+  <p id="spaces">     </p>
+  <p id="empty"></p>
+  <a href="foo" id="linkWithEqualsSign">Link=equalssign</a>
+  <p id="self-closed" />Here is some content that should not be in the previous p tag
+
+  <p class=" spaceAround ">Spaced out</p>
+
+  <span id="my_span">
+    <div>first_div</div>
+    <div>second_div</div>
+    <span>first_span</span>
+    <span>second_span</span>
+  </span>
+</body>
+</html>
diff --git a/tests/jni/Android.mk b/tests/jni/Android.mk
index d787d68..ed4c46f 100644
--- a/tests/jni/Android.mk
+++ b/tests/jni/Android.mk
@@ -22,7 +22,8 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := \
-		CtsJniOnLoad.cpp
+		CtsJniOnLoad.cpp \
+		android_os_cts_FileUtils.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) 
 
diff --git a/tests/jni/CtsJniOnLoad.cpp b/tests/jni/CtsJniOnLoad.cpp
index b6177a1..d6a1d2b 100644
--- a/tests/jni/CtsJniOnLoad.cpp
+++ b/tests/jni/CtsJniOnLoad.cpp
@@ -21,6 +21,8 @@
 extern int register_android_os_cts_CpuFeatures(JNIEnv*);
 #endif
 
+extern int register_android_os_cts_FileUtils(JNIEnv*);
+
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
 
@@ -34,5 +36,9 @@
     }
 #endif
 
+    if (register_android_os_cts_FileUtils(env)) {
+        return JNI_ERR;
+    }
+
     return JNI_VERSION_1_4;
 }
diff --git a/tests/jni/android_os_cts_FileUtils.cpp b/tests/jni/android_os_cts_FileUtils.cpp
new file mode 100644
index 0000000..d78d26c
--- /dev/null
+++ b/tests/jni/android_os_cts_FileUtils.cpp
@@ -0,0 +1,142 @@
+/* 
+ * 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 <grp.h>
+#include <jni.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static jclass gFileStatusClass;
+static jfieldID gFileStatusDevFieldID;
+static jfieldID gFileStatusInoFieldID;
+static jfieldID gFileStatusModeFieldID;
+static jfieldID gFileStatusNlinkFieldID;
+static jfieldID gFileStatusUidFieldID;
+static jfieldID gFileStatusGidFieldID;
+static jfieldID gFileStatusSizeFieldID;
+static jfieldID gFileStatusBlksizeFieldID;
+static jfieldID gFileStatusBlocksFieldID;
+static jfieldID gFileStatusAtimeFieldID;
+static jfieldID gFileStatusMtimeFieldID;
+static jfieldID gFileStatusCtimeFieldID;
+
+/*
+ * Native methods used by
+ * cts/tests/src/android/os/cts/FileUtils.java
+ *
+ * Copied from hidden API: frameworks/base/core/jni/android_os_FileUtils.cpp
+ */
+
+jboolean android_os_cts_FileUtils_getFileStatus(JNIEnv* env, jobject thiz,
+        jstring path, jobject fileStatus, jboolean statLinks)
+{
+    const char* pathStr = env->GetStringUTFChars(path, NULL);
+    jboolean ret = false;
+    struct stat s;
+
+    int res = statLinks == true ? lstat(pathStr, &s) : stat(pathStr, &s);
+
+    if (res == 0) {
+        ret = true;
+        if (fileStatus != NULL) {
+            env->SetIntField(fileStatus, gFileStatusDevFieldID, s.st_dev);
+            env->SetIntField(fileStatus, gFileStatusInoFieldID, s.st_ino);
+            env->SetIntField(fileStatus, gFileStatusModeFieldID, s.st_mode);
+            env->SetIntField(fileStatus, gFileStatusNlinkFieldID, s.st_nlink);
+            env->SetIntField(fileStatus, gFileStatusUidFieldID, s.st_uid);
+            env->SetIntField(fileStatus, gFileStatusGidFieldID, s.st_gid);
+            env->SetLongField(fileStatus, gFileStatusSizeFieldID, s.st_size);
+            env->SetIntField(fileStatus, gFileStatusBlksizeFieldID, s.st_blksize);
+            env->SetLongField(fileStatus, gFileStatusBlocksFieldID, s.st_blocks);
+            env->SetLongField(fileStatus, gFileStatusAtimeFieldID, s.st_atime);
+            env->SetLongField(fileStatus, gFileStatusMtimeFieldID, s.st_mtime);
+            env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
+        }
+    }
+
+    env->ReleaseStringUTFChars(path, pathStr);
+
+    return ret;
+}
+
+jstring android_os_cts_FileUtils_getUserName(JNIEnv* env, jobject thiz,
+        jint uid)
+{
+    struct passwd *pwd = getpwuid(uid);
+    return env->NewStringUTF(pwd->pw_name);
+}
+
+jstring android_os_cts_FileUtils_getGroupName(JNIEnv* env, jobject thiz,
+        jint gid)
+{
+    struct group *grp = getgrgid(gid);
+    return env->NewStringUTF(grp->gr_name);
+}
+
+jint android_os_cts_FileUtils_setPermissions(JNIEnv* env, jobject clazz,
+        jstring file, jint mode)
+{
+    const char *fileStr = env->GetStringUTFChars(file, NULL);
+    if (fileStr == NULL) {
+        return -1;
+    }
+
+    if (strlen(fileStr) <= 0) {
+        env->ReleaseStringUTFChars(file, fileStr);
+        return ENOENT;
+    } 
+
+    jint returnValue = chmod(fileStr, mode) == 0 ? 0 : errno;
+    env->ReleaseStringUTFChars(file, fileStr);
+    return returnValue;
+}
+
+static JNINativeMethod gMethods[] = {
+    {  "getFileStatus", "(Ljava/lang/String;Landroid/os/cts/FileUtils$FileStatus;Z)Z",
+            (void *) android_os_cts_FileUtils_getFileStatus  },
+    {  "getUserName", "(I)Ljava/lang/String;",
+            (void *) android_os_cts_FileUtils_getUserName  },
+    {  "getGroupName", "(I)Ljava/lang/String;",
+            (void *) android_os_cts_FileUtils_getGroupName  },
+    {  "setPermissions", "(Ljava/lang/String;I)I",
+            (void *) android_os_cts_FileUtils_setPermissions },
+};
+
+int register_android_os_cts_FileUtils(JNIEnv* env)
+{
+    jclass clazz = env->FindClass("android/os/cts/FileUtils");
+
+    gFileStatusClass = env->FindClass("android/os/cts/FileUtils$FileStatus");
+    gFileStatusDevFieldID = env->GetFieldID(gFileStatusClass, "dev", "I");
+    gFileStatusInoFieldID = env->GetFieldID(gFileStatusClass, "ino", "I");
+    gFileStatusModeFieldID = env->GetFieldID(gFileStatusClass, "mode", "I");
+    gFileStatusNlinkFieldID = env->GetFieldID(gFileStatusClass, "nlink", "I");
+    gFileStatusUidFieldID = env->GetFieldID(gFileStatusClass, "uid", "I");
+    gFileStatusGidFieldID = env->GetFieldID(gFileStatusClass, "gid", "I");
+    gFileStatusSizeFieldID = env->GetFieldID(gFileStatusClass, "size", "J");
+    gFileStatusBlksizeFieldID = env->GetFieldID(gFileStatusClass, "blksize", "I");
+    gFileStatusBlocksFieldID = env->GetFieldID(gFileStatusClass, "blocks", "J");
+    gFileStatusAtimeFieldID = env->GetFieldID(gFileStatusClass, "atime", "J");
+    gFileStatusMtimeFieldID = env->GetFieldID(gFileStatusClass, "mtime", "J");
+    gFileStatusCtimeFieldID = env->GetFieldID(gFileStatusClass, "ctime", "J");
+
+    return env->RegisterNatives(clazz, gMethods, 
+            sizeof(gMethods) / sizeof(JNINativeMethod)); 
+}
diff --git a/tests/res/raw/test1.obb b/tests/res/raw/test1.obb
new file mode 100644
index 0000000..a6b3e1c
--- /dev/null
+++ b/tests/res/raw/test1.obb
Binary files differ
diff --git a/tests/res/raw/test1_nosig.obb b/tests/res/raw/test1_nosig.obb
new file mode 100644
index 0000000..5c3573f
--- /dev/null
+++ b/tests/res/raw/test1_nosig.obb
Binary files differ
diff --git a/tests/res/raw/test1_wrongpackage.obb b/tests/res/raw/test1_wrongpackage.obb
new file mode 100644
index 0000000..d0aafe1
--- /dev/null
+++ b/tests/res/raw/test1_wrongpackage.obb
Binary files differ
diff --git a/tests/src/android/os/cts/FileUtils.java b/tests/src/android/os/cts/FileUtils.java
new file mode 100644
index 0000000..feaf7d7
--- /dev/null
+++ b/tests/src/android/os/cts/FileUtils.java
@@ -0,0 +1,122 @@
+/*
+ * 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.os.cts;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/** Bits and pieces copied from hidden API of android.os.FileUtils. */
+public class FileUtils {
+
+    public static final int S_IFSOCK = 0140000;
+    public static final int S_IFLNK = 0120000;
+    public static final int S_IFREG = 0100000;
+    public static final int S_IFBLK = 0060000;
+    public static final int S_IFDIR = 0040000;
+    public static final int S_IFCHR = 0020000;
+    public static final int S_IFIFO = 0010000;
+
+    public static final int S_ISUID = 0004000;
+    public static final int S_ISGID = 0002000;
+    public static final int S_ISVTX = 0001000;
+
+    public static final int S_IRWXU = 00700;
+    public static final int S_IRUSR = 00400;
+    public static final int S_IWUSR = 00200;
+    public static final int S_IXUSR = 00100;
+
+    public static final int S_IRWXG = 00070;
+    public static final int S_IRGRP = 00040;
+    public static final int S_IWGRP = 00020;
+    public static final int S_IXGRP = 00010;
+
+    public static final int S_IRWXO = 00007;
+    public static final int S_IROTH = 00004;
+    public static final int S_IWOTH = 00002;
+    public static final int S_IXOTH = 00001;
+
+    static {
+        System.loadLibrary("cts_jni");
+    }
+
+    public static class FileStatus {
+
+        public int dev;
+        public int ino;
+        public int mode;
+        public int nlink;
+        public int uid;
+        public int gid;
+        public int rdev;
+        public long size;
+        public int blksize;
+        public long blocks;
+        public long atime;
+        public long mtime;
+        public long ctime;
+
+        public boolean hasModeFlag(int flag) {
+            return (mode & flag) == flag;
+        }
+    }
+
+    /**
+     * @param path of the file to stat
+     * @param status object to set the fields on
+     * @param statLinks or don't stat links (lstat vs stat)
+     * @return whether or not we were able to stat the file
+     */
+    public native static boolean getFileStatus(String path, FileStatus status, boolean statLinks);
+
+    public native static String getUserName(int uid);
+
+    public native static String getGroupName(int gid);
+
+    public native static int setPermissions(String file, int mode);
+
+    /**
+     * Copy data from a source stream to destFile.
+     * Return true if succeed, return false if failed.
+     */
+    public static boolean copyToFile(InputStream inputStream, File destFile) {
+        try {
+            if (destFile.exists()) {
+                destFile.delete();
+            }
+            FileOutputStream out = new FileOutputStream(destFile);
+            try {
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = inputStream.read(buffer)) >= 0) {
+                    out.write(buffer, 0, bytesRead);
+                }
+            } finally {
+                out.flush();
+                try {
+                    out.getFD().sync();
+                } catch (IOException e) {
+                }
+                out.close();
+            }
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+}
diff --git a/tests/src/android/webkit/cts/CtsTestServer.java b/tests/src/android/webkit/cts/CtsTestServer.java
index 91f4f1e..707455b 100644
--- a/tests/src/android/webkit/cts/CtsTestServer.java
+++ b/tests/src/android/webkit/cts/CtsTestServer.java
@@ -79,6 +79,7 @@
 
     public static final String FAVICON_PATH = "/favicon.ico";
     public static final String USERAGENT_PATH = "/useragent.html";
+    public static final String TEST_DOWNLOAD_PATH = "/download.html";
     public static final String ASSET_PREFIX = "/assets/";
     public static final String FAVICON_ASSET_PATH = ASSET_PREFIX + "webkit/favicon.png";
     public static final String APPCACHE_PATH = "/appcache.html";
@@ -350,6 +351,10 @@
         return sb.toString();
     }
 
+    public String getTestDownloadUrl() {
+        return getBaseUri() + TEST_DOWNLOAD_PATH;
+    }
+
     public String getLastRequestUrl() {
         return mLastQuery;
     }
@@ -501,6 +506,10 @@
             }
             response.setEntity(createEntity("<html><head><title>" + agent + "</title></head>" +
                     "<body>" + agent + "</body></html>"));
+        } else if (path.equals(TEST_DOWNLOAD_PATH)) {
+            response = createResponse(HttpStatus.SC_OK);
+            response.setHeader("Content-Length", "0");
+            response.setEntity(createEntity(""));
         } else if (path.equals(SHUTDOWN_PREFIX)) {
             response = createResponse(HttpStatus.SC_OK);
             // We cannot close the socket here, because we need to respond.
diff --git a/tests/src/android/webkit/cts/WebDriverStubActivity.java b/tests/src/android/webkit/cts/WebDriverStubActivity.java
index 7ecb664..092156b 100644
--- a/tests/src/android/webkit/cts/WebDriverStubActivity.java
+++ b/tests/src/android/webkit/cts/WebDriverStubActivity.java
@@ -49,7 +49,6 @@
         setContentView(view);
     }
 
-
     public WebDriver getDriver() {
         return mDriver;
     }
diff --git a/tests/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
new file mode 100644
index 0000000..fbe57c4
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.app.cts;
+
+import android.app.DownloadManager;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.Cursor;
+import android.net.Uri;
+import android.test.AndroidTestCase;
+import android.view.animation.cts.DelayedCheck;
+import android.webkit.cts.CtsTestServer;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class DownloadManagerTest extends AndroidTestCase {
+
+    private DownloadManager mDownloadManager;
+
+    private CtsTestServer mWebServer;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
+        mWebServer = new CtsTestServer(mContext);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mWebServer.shutdown();
+    }
+
+    public void testDownloadManager() throws Exception {
+        DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+        try {
+            removeAllDownloads();
+
+            IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+            mContext.registerReceiver(receiver, intentFilter);
+
+            long goodId = mDownloadManager.enqueue(new Request(getGoodUrl()));
+            long badId = mDownloadManager.enqueue(new Request(getBadUrl()));
+
+            int allDownloads = getTotalNumberDownloads();
+            assertEquals(2, allDownloads);
+
+            assertDownloadQueryableById(goodId);
+            assertDownloadQueryableById(badId);
+
+            receiver.waitForDownloadComplete();
+
+            assertDownloadQueryableByStatus(DownloadManager.STATUS_SUCCESSFUL);
+            assertDownloadQueryableByStatus(DownloadManager.STATUS_FAILED);
+
+            assertRemoveDownload(goodId, allDownloads - 1);
+            assertRemoveDownload(badId, allDownloads - 2);
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    private class DownloadCompleteReceiver extends BroadcastReceiver {
+
+        private final CountDownLatch mReceiveLatch = new CountDownLatch(2);
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mReceiveLatch.countDown();
+        }
+
+        public void waitForDownloadComplete() throws InterruptedException {
+            assertTrue("Make sure you have WiFi or some other connectivity for this test.",
+                    mReceiveLatch.await(3, TimeUnit.SECONDS));
+        }
+    }
+
+    private void removeAllDownloads() {
+        if (getTotalNumberDownloads() > 0) {
+            Cursor cursor = null;
+            try {
+                Query query = new Query();
+                cursor = mDownloadManager.query(query);
+                int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_ID);
+                long[] removeIds = new long[cursor.getCount()];
+                for (int i = 0; cursor.moveToNext(); i++) {
+                    removeIds[i] = cursor.getLong(columnIndex);
+                }
+                assertEquals(removeIds.length, mDownloadManager.remove(removeIds));
+                assertEquals(0, getTotalNumberDownloads());
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+        }
+    }
+
+    private Uri getGoodUrl() {
+        return Uri.parse(mWebServer.getTestDownloadUrl());
+    }
+
+    private Uri getBadUrl() {
+        return Uri.parse(mWebServer.getBaseUri() + "/nosuchurl");
+    }
+
+    private int getTotalNumberDownloads() {
+        Cursor cursor = null;
+        try {
+            Query query = new Query();
+            cursor = mDownloadManager.query(query);
+            return cursor.getCount();
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+
+    private void assertDownloadQueryableById(long downloadId) {
+        Cursor cursor = null;
+        try {
+            Query query = new Query().setFilterById(downloadId);
+            cursor = mDownloadManager.query(query);
+            assertEquals(1, cursor.getCount());
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+
+    private void assertDownloadQueryableByStatus(final int status) {
+        new DelayedCheck() {
+            @Override
+            protected boolean check() {
+                Cursor cursor= null;
+                try {
+                    Query query = new Query().setFilterByStatus(status);
+                    cursor = mDownloadManager.query(query);
+                    return 1 == cursor.getCount();
+                } finally {
+                    if (cursor != null) {
+                        cursor.close();
+                    }
+                }
+            }
+        }.run();
+    }
+
+    private void assertRemoveDownload(long removeId, int expectedNumDownloads) {
+        Cursor cursor = null;
+        try {
+            assertEquals(1, mDownloadManager.remove(removeId));
+            Query query = new Query();
+            cursor = mDownloadManager.query(query);
+            assertEquals(expectedNumDownloads, cursor.getCount());
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+}
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
new file mode 100644
index 0000000..b229d03
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -0,0 +1,257 @@
+/*
+ * 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.os.storage.cts;
+
+import com.android.cts.stub.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.os.cts.FileUtils;
+import android.os.storage.OnObbStateChangeListener;
+import android.os.storage.StorageManager;
+import android.test.AndroidTestCase;
+import android.test.ComparisonFailure;
+import android.util.Log;
+
+import java.io.File;
+import java.io.InputStream;
+
+public class StorageManagerTest extends AndroidTestCase {
+
+    private static final String TAG = StorageManager.class.getSimpleName();
+
+    private static final long MAX_WAIT_TIME = 25*1000;
+    private static final long WAIT_TIME_INCR = 5*1000;
+
+    private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
+
+    private StorageManager mStorageManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
+    }
+
+    public void testMountAndUnmountObbNormal() {
+        final File outFile = getFilePath("test1.obb");
+
+        mountObb(R.raw.test1, outFile, OnObbStateChangeListener.MOUNTED);
+
+        mountObb(R.raw.test1, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
+
+        final String mountPath = checkMountedPath(outFile);
+        final File mountDir = new File(mountPath);
+
+        assertTrue("OBB mounted path should be a directory", mountDir.isDirectory());
+
+        unmountObb(outFile, OnObbStateChangeListener.UNMOUNTED);
+    }
+
+    public void testAttemptMountNonObb() {
+        final File outFile = getFilePath("test1_nosig.obb");
+
+        mountObb(R.raw.test1_nosig, outFile, OnObbStateChangeListener.ERROR_INTERNAL);
+
+        assertFalse("OBB should not be mounted",
+                mStorageManager.isObbMounted(outFile.getPath()));
+
+        assertNull("OBB's mounted path should be null",
+                mStorageManager.getMountedObbPath(outFile.getPath()));
+    }
+
+    public void testAttemptMountObbWrongPackage() {
+        final File outFile = getFilePath("test1_wrongpackage.obb");
+
+        mountObb(R.raw.test1_wrongpackage, outFile,
+                OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+
+        assertFalse("OBB should not be mounted",
+                mStorageManager.isObbMounted(outFile.getPath()));
+
+        assertNull("OBB's mounted path should be null",
+                mStorageManager.getMountedObbPath(outFile.getPath()));
+    }
+
+    public void testMountAndUnmountTwoObbs() {
+        final File file1 = getFilePath("test1.obb");
+        final File file2 = getFilePath("test2.obb");
+
+        ObbObserver oo1 = mountObbWithoutWait(R.raw.test1, file1);
+        ObbObserver oo2 = mountObbWithoutWait(R.raw.test1, file2);
+
+        Log.d(TAG, "Waiting for OBB #1 to complete mount");
+        waitForObbActionCompletion(file1, oo1, OnObbStateChangeListener.MOUNTED, false);
+        Log.d(TAG, "Waiting for OBB #2 to complete mount");
+        waitForObbActionCompletion(file2, oo2, OnObbStateChangeListener.MOUNTED, false);
+
+        final String mountPath1 = checkMountedPath(file1);
+        final File mountDir1 = new File(mountPath1);
+        assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory());
+
+        final String mountPath2 = checkMountedPath(file2);
+        final File mountDir2 = new File(mountPath2);
+        assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory());
+
+        unmountObb(file1, OnObbStateChangeListener.UNMOUNTED);
+        unmountObb(file2, OnObbStateChangeListener.UNMOUNTED);
+    }
+
+    private static void assertStartsWith(String message, String prefix, String actual) {
+        if (!actual.startsWith(prefix)) {
+            throw new ComparisonFailure(message, prefix, actual);
+        }
+    }
+
+    private static class ObbObserver extends OnObbStateChangeListener {
+        private String path;
+
+        public int state = -1;
+        boolean done = false;
+
+        @Override
+        public void onObbStateChange(String path, int state) {
+            Log.d(TAG, "Received message.  path=" + path + ", state=" + state);
+            synchronized (this) {
+                this.path = path;
+                this.state = state;
+                done = true;
+                notifyAll();
+            }
+        }
+
+        public String getPath() {
+            assertTrue("Expected ObbObserver to have received a state change.", done);
+            return path;
+        }
+
+        public int getState() {
+            assertTrue("Expected ObbObserver to have received a state change.", done);
+            return state;
+        }
+
+        public boolean isDone() {
+            return done;
+        }
+
+        public boolean waitForCompletion() {
+            long waitTime = 0;
+            synchronized (this) {
+                while (!isDone() && waitTime < MAX_WAIT_TIME) {
+                    try {
+                        wait(WAIT_TIME_INCR);
+                        waitTime += WAIT_TIME_INCR;
+                    } catch (InterruptedException e) {
+                        Log.i(TAG, "Interrupted during sleep", e);
+                    }
+                }
+            }
+
+            return isDone();
+        }
+    }
+
+    private File getFilePath(String name) {
+        final File filesDir = mContext.getFilesDir();
+        final File outFile = new File(filesDir, name);
+        return outFile;
+    }
+
+    private void copyRawToFile(int rawResId, File outFile) {
+        Resources res = mContext.getResources();
+        InputStream is = null;
+        try {
+            is = res.openRawResource(rawResId);
+        } catch (NotFoundException e) {
+            fail("Failed to load resource with id: " + rawResId);
+        }
+        FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+                | FileUtils.S_IRWXO);
+        assertTrue(FileUtils.copyToFile(is, outFile));
+        FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+                | FileUtils.S_IRWXO);
+    }
+
+    private void mountObb(final int resource, final File file, int expectedState) {
+        copyRawToFile(resource, file);
+
+        final ObbObserver observer = new ObbObserver();
+        assertTrue("mountObb call on " + file.getPath() + " should succeed",
+                mStorageManager.mountObb(file.getPath(), null, observer));
+
+        assertTrue("Mount should have completed",
+                observer.waitForCompletion());
+
+        if (expectedState == OnObbStateChangeListener.MOUNTED) {
+            assertTrue("OBB should be mounted", mStorageManager.isObbMounted(file.getPath()));
+        }
+
+        assertEquals("Actual file and resolved file should be the same",
+                file.getPath(), observer.getPath());
+
+        assertEquals(expectedState, observer.getState());
+    }
+
+    private ObbObserver mountObbWithoutWait(final int resource, final File file) {
+        copyRawToFile(resource, file);
+
+        final ObbObserver observer = new ObbObserver();
+        assertTrue("mountObb call on " + file.getPath() + " should succeed",
+                mStorageManager.mountObb(file.getPath(), null, observer));
+
+        return observer;
+    }
+
+    private void waitForObbActionCompletion(final File file,
+            final ObbObserver observer, int expectedState, boolean checkPath) {
+        assertTrue("Mount should have completed", observer.waitForCompletion());
+
+        assertTrue("OBB should be mounted", mStorageManager.isObbMounted(file.getPath()));
+
+        if (checkPath) {
+            assertEquals("Actual file and resolved file should be the same", file.getPath(),
+                    observer.getPath());
+        }
+
+        assertEquals(expectedState, observer.getState());
+    }
+
+    private String checkMountedPath(final File file) {
+        final String mountPath = mStorageManager.getMountedObbPath(file.getPath());
+        assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX,
+                OBB_MOUNT_PREFIX,
+                mountPath);
+        return mountPath;
+    }
+
+    private void unmountObb(final File file, int expectedState) {
+        final ObbObserver observer = new ObbObserver();
+
+        assertTrue("unmountObb call on test1.obb should succeed",
+                mStorageManager.unmountObb(file.getPath(), false, observer));
+
+        assertTrue("Unmount should have completed",
+                observer.waitForCompletion());
+
+        assertEquals(expectedState, observer.getState());
+
+        if (expectedState == OnObbStateChangeListener.UNMOUNTED) {
+            assertFalse("OBB should not be mounted", mStorageManager.isObbMounted(file.getPath()));
+        }
+    }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java b/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java
index b6afb70..aa981ca 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java
@@ -216,7 +216,7 @@
         }
 
         try {
-            int invalidUsage = 0x0010;
+            int invalidUsage = 0x0020;
             Allocation.createFromBitmap(mRS, B,
                 Allocation.MipmapControl.MIPMAP_NONE, invalidUsage);
             fail("should throw RSIllegalArgumentException.");
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ElementTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ElementTest.java
index 7723c20..0f58d55 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/ElementTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ElementTest.java
@@ -244,8 +244,9 @@
         assertEquals(DataKind.PIXEL_LA, DataKind.valueOf("PIXEL_LA"));
         assertEquals(DataKind.PIXEL_RGB, DataKind.valueOf("PIXEL_RGB"));
         assertEquals(DataKind.PIXEL_RGBA, DataKind.valueOf("PIXEL_RGBA"));
+        assertEquals(DataKind.PIXEL_DEPTH, DataKind.valueOf("PIXEL_DEPTH"));
         // Make sure no new enums are added
-        assertEquals(6, DataKind.values().length);
+        assertEquals(7, DataKind.values().length);
 
         for (DataKind dk : DataKind.values()) {
             if (dk != DataKind.USER) {
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
index 80d44f7..d7233d5 100755
--- a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
@@ -64,7 +64,8 @@
                     "45002",    // SKT Mobility
                     "45008",    // KT Mobility
                     "45006",    // LGT
-                    "311660"    // MetroPCS
+                    "311660",   // MetroPCS
+                    "310120"    // Sprint
             );
 
     // List of network operators that doesn't support Data(binary) SMS message
diff --git a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
index b2bdfc8..51f1201 100644
--- a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
+++ b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
@@ -54,6 +54,8 @@
     public static final String BLANK_PAGE_URL = "webkit/test_blankPage.html";
     public static final String ADD_JAVA_SCRIPT_INTERFACE_URL = "webkit/test_jsInterface.html";
 
+    public static final String FORM_PAGE_URL = "webkit/form_page.html";
+
     public static final String EXT_WEB_URL1 = "http://www.example.com/";
 
     public static final String getFileUrl(String assetName) {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebDriverTest.java b/tests/tests/webkit/src/android/webkit/cts/WebDriverTest.java
index cd40caf..93c7b5f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebDriverTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebDriverTest.java
@@ -17,8 +17,18 @@
 package android.webkit.cts;
 
 import android.test.ActivityInstrumentationTestCase2;
+import android.webkit.webdriver.By;
 import android.webkit.webdriver.WebDriver;
+import android.webkit.webdriver.WebElement;
+import android.webkit.webdriver.WebElementNotFoundException;
+import android.webkit.webdriver.WebElementStaleException;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static android.webkit.cts.TestHtmlConstants.FORM_PAGE_URL;
 import static android.webkit.cts.TestHtmlConstants.HELLO_WORLD_URL;
 
 /**
@@ -28,6 +38,13 @@
         ActivityInstrumentationTestCase2<WebDriverStubActivity>{
     private WebDriver mDriver;
     private CtsTestServer mWebServer;
+    private static final String SOME_TEXT = "Some text";
+    private static final String DIV_TEXT = "A div Nested text";
+    private static final String NESTED_TEXT = "Nested text";
+    private static final String DIV_ID = "divId";
+    private static final String SOME_TEXT_ID = "someTextId";
+    private static final String BAD_ID = "BadId";
+    private static final String NESTED_LINK_ID = "nestedLinkId";
 
     public WebDriverTest() {
         super(WebDriverStubActivity.class);
@@ -50,4 +67,415 @@
         mDriver.get(mWebServer.getDelayedAssetUrl(HELLO_WORLD_URL));
         assertTrue(mDriver.getPageSource().contains("hello world!"));
     }
+
+    // By id
+    public void testFindElementById() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement element = mDriver.findElement(By.id(SOME_TEXT_ID));
+        assertTrue(SOME_TEXT.equals(element.getText()));
+
+        element = mDriver.findElement(By.id(DIV_ID));
+        assertTrue(DIV_TEXT.equals(element.getText()));
+    }
+
+    public void testFindElementByIdThrowsIfElementDoesNotExists() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.findElement(By.id(BAD_ID));
+            fail("This should have failed.");
+        } catch (WebElementNotFoundException e) {
+            // This is expected
+        }
+    }
+
+    public void testFindNestedElementById() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement parent = mDriver.findElement(By.id(DIV_ID));
+        WebElement nestedNode = parent.findElement(By.id(NESTED_LINK_ID));
+        assertTrue(NESTED_TEXT.equals(nestedNode.getText()));
+    }
+
+    // By linkText
+    public void testFindElementByLinkText() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement element = mDriver.findElement(By.id(SOME_TEXT_ID));
+        assertTrue(SOME_TEXT.equals(element.getText()));
+
+        element = mDriver.findElement(By.id(DIV_ID));
+        assertTrue(DIV_TEXT.equals(element.getText()));
+    }
+
+    public void testFindElementByLinkTextThrowsIfElementDoesNotExists() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.findElement(By.id(BAD_ID));
+            fail("This should have failed.");
+        } catch (WebElementNotFoundException e) {
+            // This is expected
+        }
+    }
+
+    public void testFindNestedElementByLinkText() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement parent = mDriver.findElement(By.id(DIV_ID));
+        WebElement nestedNode = parent.findElement(By.id(NESTED_LINK_ID));
+        assertTrue(NESTED_TEXT.equals(nestedNode.getText()));
+    }
+
+    // By partialLinkText
+    public void testFindElementByPartialLinkText() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement element = mDriver.findElement(By.id(SOME_TEXT_ID));
+        assertTrue(SOME_TEXT.equals(element.getText()));
+
+        element = mDriver.findElement(By.id(DIV_ID));
+        assertTrue(DIV_TEXT.equals(element.getText()));
+    }
+
+    public void testFindElementByPartialLinkTextThrowsIfElementDoesNotExists() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.findElement(By.id(BAD_ID));
+            fail("This should have failed.");
+        } catch (WebElementNotFoundException e) {
+            // This is expected
+        }
+    }
+
+    public void testFindNestedElementByPartialLinkText() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement parent = mDriver.findElement(By.id(DIV_ID));
+        WebElement nestedNode = parent.findElement(By.id(NESTED_LINK_ID));
+        assertTrue(NESTED_TEXT.equals(nestedNode.getText()));
+    }
+
+    // by name
+    public void testFindElementByName() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement element = mDriver.findElement(By.id(SOME_TEXT_ID));
+        assertTrue(SOME_TEXT.equals(element.getText()));
+
+        element = mDriver.findElement(By.id(DIV_ID));
+        assertTrue(DIV_TEXT.equals(element.getText()));
+    }
+
+    public void testFindElementByNameThrowsIfElementDoesNotExists() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.findElement(By.id(BAD_ID));
+            fail("This should have failed.");
+        } catch (WebElementNotFoundException e) {
+            // This is expected
+        }
+    }
+
+    public void testFindNestedElementByName() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement parent = mDriver.findElement(By.id(DIV_ID));
+        WebElement nestedNode = parent.findElement(By.id(NESTED_LINK_ID));
+        assertTrue(NESTED_TEXT.equals(nestedNode.getText()));
+    }
+
+    // By tagName
+    public void testFindElementByTagName() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement element = mDriver.findElement(By.id(SOME_TEXT_ID));
+        assertTrue(SOME_TEXT.equals(element.getText()));
+
+        element = mDriver.findElement(By.id(DIV_ID));
+        assertTrue(DIV_TEXT.equals(element.getText()));
+    }
+
+    public void testFindElementByTagNameThrowsIfElementDoesNotExists() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.findElement(By.id(BAD_ID));
+            fail("This should have failed.");
+        } catch (WebElementNotFoundException e) {
+            // This is expected
+        }
+    }
+
+    public void testFindNestedElementByTagName() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement parent = mDriver.findElement(By.id(DIV_ID));
+        WebElement nestedNode = parent.findElement(By.id(NESTED_LINK_ID));
+        assertTrue(NESTED_TEXT.equals(nestedNode.getText()));
+    }
+
+    // By xpath
+    public void testFindElementByXPath() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement element = mDriver.findElement(By.id(SOME_TEXT_ID));
+        assertTrue(SOME_TEXT.equals(element.getText()));
+
+        element = mDriver.findElement(By.id(DIV_ID));
+        assertTrue(DIV_TEXT.equals(element.getText()));
+    }
+
+    public void testFindElementByXPathThrowsIfElementDoesNotExists() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.findElement(By.id(BAD_ID));
+            fail("This should have failed.");
+        } catch (WebElementNotFoundException e) {
+            // This is expected
+        }
+    }
+
+    public void testFindNestedElementByXPath() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement parent = mDriver.findElement(By.id(DIV_ID));
+        WebElement nestedNode = parent.findElement(By.id(NESTED_LINK_ID));
+        assertTrue(NESTED_TEXT.equals(nestedNode.getText()));
+    }
+
+    public void testGetTextThrowsIfElementIsStale() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement div = mDriver.findElement(By.id(DIV_ID));
+        mDriver.get(mWebServer.getAssetUrl(HELLO_WORLD_URL));
+        try {
+            div.getText();
+            fail("This should have failed.");
+        } catch (WebElementStaleException e) {
+            // This is expected
+        }
+    }
+
+    public void testExecuteScriptShouldReturnAString() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Object result = mDriver.executeScript("return document.title");
+        assertEquals("Test Page", (String) result);
+    }
+
+    public void testExecuteScriptShouldReturnAWebElement() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Object result = mDriver.executeScript(
+                "return document.getElementsByTagName('div')[0];");
+        assertTrue(result instanceof WebElement);
+        assertEquals(DIV_TEXT, ((WebElement) result).getText());
+    }
+
+    public void testExecuteScriptShouldPassAndReturnADouble() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Double expected = new Double(1.2);
+        Object result = mDriver.executeScript("return arguments[0];", expected);
+        assertTrue(result instanceof Double);
+        assertEquals(expected, (Double) result);
+    }
+
+    public void testExecuteScriptShouldPassAndReturnALong() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Long expected = new Long(1);
+        Object result = mDriver.executeScript("return arguments[0];", expected);
+        assertTrue(result instanceof Long);
+        assertEquals(expected, (Long) result);
+    }
+
+    public void testExecuteScriptShouldPassReturnABoolean() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Boolean expected = new Boolean(true);
+        Object result = mDriver.executeScript("return arguments[0] === true;",
+                expected);
+        assertTrue(result instanceof Boolean);
+        assertEquals(expected, (Boolean) result);
+    }
+
+    public void testExecuteScriptShouldReturnAList() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        List<String> expected = new ArrayList();
+        expected.add("one");
+        expected.add("two");
+        expected.add("three");
+
+        Object result = mDriver.executeScript(
+                "return ['one', 'two', 'three'];");
+
+        assertTrue(expected.equals((List<String>) result));
+    }
+
+    public void testExecuteScriptShouldReturnNestedList() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        List<Object> expected = new ArrayList();
+        expected.add("one");
+        List<Object> nestedList = new ArrayList();
+        nestedList.add(true);
+        nestedList.add(false);
+        expected.add(nestedList);
+        Map<String, Object> nestedMap = new HashMap();
+        nestedMap.put("bread", "cheese");
+        nestedMap.put("hungry", true);
+        expected.add(nestedMap);
+
+        Object result = mDriver.executeScript(
+                "return ['one', [true, false], "
+                + "{bread:'cheese', hungry:true}];");
+
+        assertTrue(expected.equals(result));
+    }
+
+    public void testExecuteScriptShouldBeAbleToReturnALisOfwebElements() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        List<WebElement> result = (List<WebElement>) mDriver.executeScript(
+                "return document.getElementsByTagName('a')");
+        assertEquals(5, result.size());
+    }
+
+    public void testExecuteScriptShouldReturnAMap() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Map<String, Object> expected = new HashMap();
+        expected.put("abc", Long.valueOf(123));
+        expected.put("cat", false);
+        Map<String, Object> nestedMap = new HashMap();
+        nestedMap.put("bread", "cheese");
+        nestedMap.put("hungry", true);
+        expected.put("map", nestedMap);
+        List<String> nestedList = new ArrayList();
+        nestedList.add("bou");
+        nestedList.add("truc");
+        expected.put("list", nestedList);
+
+        Object res = mDriver.executeScript("return {abc:123, cat:false, "
+                + "map:{bread:'cheese', hungry:true}, list:['bou', 'truc']};");
+        assertTrue(res instanceof Map);
+        Map<String, Object> result = (Map<String, Object>) res;
+        assertEquals(expected.size(), result.size());
+
+        assertTrue(expected.equals(result));
+    }
+
+    public void testExecuteScriptShouldThrowIfJsIsBad() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.executeScript("return bou();");
+            fail("This should have failed");
+        } catch (RuntimeException e) {
+            // This is expected.
+        }
+    }
+
+    public void testExecuteScriptShouldbeAbleToPassAString() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        String expected = "bou";
+        Object result = mDriver.executeScript("return arguments[0]", expected);
+        assertEquals(expected, (String) result);
+    }
+
+    public void testExecuteScriptShouldBeAbleToPassWebElement() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        WebElement div = mDriver.findElement(By.id(DIV_ID));
+        Object result = mDriver.executeScript(
+                "arguments[0]['flibble'] = arguments[0].getAttribute('id');"
+                + "return arguments[0]['flibble'];", div);
+        assertEquals(DIV_ID, (String) result);
+    }
+
+    public void testExecuteScriptShouldBeAbleToPassAList() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        List<String> expected = new ArrayList();
+        expected.add("apple");
+        expected.add("cheese");
+        expected.add("food");
+
+        Object result = mDriver.executeScript(
+                "return arguments[0].length", expected);
+        assertEquals(expected.size(), ((Long) result).intValue());
+    }
+
+    public void testExecuteScriptShouldBeAbleToPassNestedLists() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        List<Object> expected = new ArrayList();
+        expected.add("apple");
+        expected.add("cheese");
+        List<Integer> nested = new ArrayList();
+        nested.add(1);
+        nested.add(2);
+        expected.add(nested);
+        expected.add("food");
+
+        Object result = mDriver.executeScript(
+                "return arguments[0][2].length", expected);
+        assertEquals(nested.size(), ((Long) result).intValue());
+    }
+
+    public void testExecuteScriptShouldBeAbleToPassAMap() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Map<String, String> expected = new HashMap();
+        expected.put("apple", "pie");
+        expected.put("cheese", "cake");
+
+        Object result = mDriver.executeScript(
+                "return arguments[0].apple", expected);
+        assertEquals(expected.get("apple"), (String) result);
+    }
+
+    public void testExecuteScriptShouldBeAbleToPassNestedMaps() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        Map<String, Object> expected = new HashMap();
+        expected.put("apple", "pie");
+        Map<String, String> nested = new HashMap();
+        nested.put("foo", "boo");
+        expected.put("nested", nested);
+        expected.put("cheese", "cake");
+
+        Object result = mDriver.executeScript(
+                "return arguments[0].nested.foo", expected);
+        assertEquals(((Map<String, Object>)expected.get("nested")).get("foo"),
+                (String) result);
+    }
+
+
+    public void testExecuteScriptShouldThrowIfArgumentIsNotValid() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        try {
+            mDriver.executeScript("return arguments[0];", mDriver);
+            fail("This should have failed");
+        } catch (RuntimeException e) {
+            // This is expected.
+        }
+    }
+
+    public void testExecuteScriptHandlesStringCorrectly() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        String cheese = "cheese";
+        String bread = "bread";
+        Object result = mDriver.executeScript(
+                "return 'I love ' + arguments[0] + ' and ' + arguments[1]",
+                cheese, bread);
+        assertEquals("I love cheese and bread", (String) result);
+    }
+
+    public void testExecuteScriptShouldThrowIfNoPageLoaded() {
+        try {
+            mDriver.executeScript("return 'bou';");
+            fail("This should have failed");
+        } catch (RuntimeException e) {
+            // This is expected.
+        }
+    }
+
+    public void testExecuteScriptShouldBeAbleToCreatePersistentValue() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        mDriver.executeScript("document.bidule = ['hello']");
+        Object result = mDriver.executeScript(
+                "return document.bidule.shift();");
+        assertEquals("hello", (String) result);
+    }
+
+    public void testExecuteScriptEscapesQuotesAndBackslash() {
+        mDriver.get(mWebServer.getAssetUrl(FORM_PAGE_URL));
+        assertTrue((Boolean) mDriver.executeScript(
+                "return \"foo'\\\"\" == arguments[0];", "foo'\""));
+        assertTrue((Boolean) mDriver.executeScript(
+                "return \"foo'\\\"bar\" == arguments[0];", "foo'\"bar"));
+        assertTrue((Boolean) mDriver.executeScript(
+                "return 'foo\"' == arguments[0];", "foo\""));
+        assertTrue((Boolean) mDriver.executeScript(
+                "return \"foo'\" == arguments[0];", "foo'"));
+        assertTrue((Boolean) mDriver.executeScript(
+                "return \"foo\\\\\\\"\" == arguments[0];", "foo\\\""));
+        assertTrue((Boolean) mDriver.executeScript(
+                "return \"f\\\"o\\\\o\\\\\\\\\\\"\" == arguments[0];",
+                "f\"o\\o\\\\\""));
+    }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
index 4a2d56c..9bc0945 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.tradefed.build;
 
+import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.build.IFolderBuildInfo;
 
 import java.io.File;
@@ -57,6 +58,29 @@
     }
 
     /**
+     * A helper factory method that creates and validates a {@link CtsBuildHelper} given an
+     * {@link IBuildInfo}.
+     *
+     * @param build the {@link IBuildInfo}
+     * @return the {@link CtsBuildHelper}
+     * @throws IllegalArgumentException if provided <var>build</var> is not a valid CTS build
+     */
+    public static CtsBuildHelper createBuildHelper(IBuildInfo build) {
+        if (!(build instanceof IFolderBuildInfo)) {
+            throw new IllegalArgumentException(String.format(
+                    "Wrong build type. Expected %s, received %s", IFolderBuildInfo.class.getName(),
+                    build.getClass().getName()));
+        }
+        try {
+            CtsBuildHelper ctsBuild = new CtsBuildHelper((IFolderBuildInfo)build);
+            ctsBuild.validateStructure();
+            return ctsBuild;
+        } catch (FileNotFoundException e) {
+            throw new IllegalArgumentException("Invalid CTS build provided.", e);
+        }
+    }
+
+    /**
      * @return a {@link File} representing the parent folder of the CTS installation
      */
     public File getRootDir() {
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index f49c4a0..f6d8142 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -22,7 +22,6 @@
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -201,18 +200,8 @@
      */
     @Override
     public void setBuild(IBuildInfo build) {
-        if (!(build instanceof IFolderBuildInfo)) {
-            throw new IllegalArgumentException(String.format(
-                    "Wrong build type. Expected %s, received %s", IFolderBuildInfo.class.getName(),
-                    build.getClass().getName()));
-        }
-        try {
-            mBuildInfo = build;
-            mCtsBuild = new CtsBuildHelper((IFolderBuildInfo)build);
-            mCtsBuild.validateStructure();
-        } catch (FileNotFoundException e) {
-            throw new IllegalArgumentException("Invalid CTS build provided.", e);
-        }
+        mCtsBuild = CtsBuildHelper.createBuildHelper(build);
+        mBuildInfo = build;
     }
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/InstrumentationApkTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/InstrumentationApkTest.java
index b3d2eec..e1bb91e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/InstrumentationApkTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/InstrumentationApkTest.java
@@ -18,7 +18,6 @@
 import com.android.cts.tradefed.build.CtsBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.testtype.IBuildReceiver;
@@ -49,17 +48,7 @@
      */
     @Override
     public void setBuild(IBuildInfo build) {
-        if (!(build instanceof IFolderBuildInfo)) {
-            throw new IllegalArgumentException(String.format(
-                    "Wrong build type. Expected %s, received %s", IFolderBuildInfo.class.getName(),
-                    build.getClass().getName()));
-        }
-        try {
-            mCtsBuild  = new CtsBuildHelper((IFolderBuildInfo)build);
-            mCtsBuild.validateStructure();
-        } catch (FileNotFoundException e) {
-            throw new IllegalArgumentException("Invalid CTS build provided.", e);
-        }
+        mCtsBuild  = CtsBuildHelper.createBuildHelper(build);
     }
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
index 041079d..2fe6802 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
@@ -15,12 +15,15 @@
  */
 package com.android.cts.tradefed.testtype;
 
+import com.android.cts.tradefed.build.CtsBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.result.JUnitToInvocationResultForwarder;
+import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IDeviceTest;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.util.CommandStatus;
@@ -28,6 +31,7 @@
 import com.android.tradefed.util.RunUtil;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -39,29 +43,50 @@
 import junit.framework.TestResult;
 
 /**
- * A {@link IRemoteTest} that can run a set of JUnit tests from a jar.
+ * A {@link IRemoteTest} that can run a set of JUnit tests from a CTS jar.
  */
-public class JarHostTest implements IDeviceTest, IRemoteTest {
+public class JarHostTest implements IDeviceTest, IRemoteTest, IBuildReceiver {
 
     private static final String LOG_TAG = "JarHostTest";
 
     private ITestDevice mDevice;
-    private File mJarFile;
+    private String mJarFileName;
     private Collection<TestIdentifier> mTests;
     private long mTimeoutMs = 10 * 60 * 1000;
     private String mRunName;
-    private String mTestAppPath;
+    private CtsBuildHelper mCtsBuild = null;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+    }
+
+    /**
+     * Set the CTS build container.
+     * <p/>
+     * Exposed so unit tests can mock the provided build.
+     *
+     * @param buildHelper
+     */
+    void setBuildHelper(CtsBuildHelper buildHelper) {
+        mCtsBuild = buildHelper;
+    }
 
     /**
      * Set the jar file to load tests from.
-     * @param jarFile
+     *
+     * @param jarFileName the file name of the CTS host test jar to use
      */
-    void setJarFile(File jarFile) {
-        mJarFile = jarFile;
+    void setJarFileName(String jarFileName) {
+        mJarFileName = jarFileName;
     }
 
     /**
      * Sets the collection of tests to run
+     *
      * @param tests
      */
     void setTests(Collection<TestIdentifier> tests) {
@@ -90,17 +115,6 @@
     }
 
     /**
-     * Set the filesystem path to test app artifacts needed to run tests.
-     *
-     * @see {@link com.android.hosttest.DeviceTest#setTestAppPath(String)}
-     *
-     * @param testAppPath
-     */
-    void setTestAppPath(String testAppPath) {
-        mTestAppPath = testAppPath;
-    }
-
-    /**
      * {@inheritDoc}
      */
     @Override
@@ -153,7 +167,7 @@
             // all host tests are converted to use tradefed
             com.android.hosttest.DeviceTest deviceTest = (com.android.hosttest.DeviceTest)junitTest;
             deviceTest.setDevice(getDevice().getIDevice());
-            deviceTest.setTestAppPath(mTestAppPath);
+            deviceTest.setTestAppPath(mCtsBuild.getTestCasesDir().getAbsolutePath());
         }
         CommandStatus status = RunUtil.getInstance().runTimed(mTimeoutMs, new IRunnableResult() {
 
@@ -183,7 +197,8 @@
      */
     private Test loadTest(String className, String testName) {
         try {
-            URL urls[] = {mJarFile.getCanonicalFile().toURI().toURL()};
+            File jarFile = mCtsBuild.getTestApp(mJarFileName);
+            URL urls[] = {jarFile.getCanonicalFile().toURI().toURL()};
             Class<?> testClass = loadClass(className, urls);
 
             if (TestCase.class.isAssignableFrom(testClass)) {
@@ -195,16 +210,16 @@
                 return test;
             } else {
                 Log.e(LOG_TAG, String.format("Class '%s' from jar '%s' is not a Test",
-                        className, mJarFile.getAbsolutePath()));
+                        className, mJarFileName));
             }
         } catch (ClassNotFoundException e) {
-            reportLoadError(mJarFile, className, e);
+            reportLoadError(mJarFileName, className, e);
         } catch (IllegalAccessException e) {
-            reportLoadError(mJarFile, className, e);
+            reportLoadError(mJarFileName, className, e);
         } catch (IOException e) {
-            reportLoadError(mJarFile, className, e);
+            reportLoadError(mJarFileName, className, e);
         } catch (InstantiationException e) {
-            reportLoadError(mJarFile, className, e);
+            reportLoadError(mJarFileName, className, e);
         }
         return null;
     }
@@ -225,9 +240,9 @@
         return testClass;
     }
 
-    private void reportLoadError(File jarFile, String className, Exception e) {
+    private void reportLoadError(String jarFileName, String className, Exception e) {
         Log.e(LOG_TAG, String.format("Failed to load test class '%s' from jar '%s'",
-                className, jarFile.getAbsolutePath()));
+                className, jarFileName));
         Log.e(LOG_TAG, e);
     }
 
@@ -241,11 +256,21 @@
         if (mDevice == null) {
             throw new IllegalArgumentException("Device has not been set");
         }
-        if (mJarFile == null) {
-            throw new IllegalArgumentException("jar file has not been set");
+        if (mJarFileName == null) {
+            throw new IllegalArgumentException("jar file name has not been set");
         }
         if (mTests == null) {
             throw new IllegalArgumentException("tests has not been set");
         }
+        if (mCtsBuild == null) {
+            throw new IllegalArgumentException("build has not been set");
+        }
+        try {
+            mCtsBuild.getTestApp(mJarFileName);
+        } catch (FileNotFoundException e) {
+            throw new IllegalArgumentException(String.format(
+                    "Could not find jar %s in CTS build %s", mJarFileName,
+                    mCtsBuild.getRootDir().getAbsolutePath()));
+        }
     }
 }
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 6b165be..04da318 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
@@ -136,8 +136,7 @@
             Log.d(LOG_TAG, String.format("Creating host test for %s", mName));
             JarHostTest hostTest = new JarHostTest();
             hostTest.setRunName(mName);
-            hostTest.setJarFile(new File(testCaseDir, mJarPath));
-            hostTest.setTestAppPath(testCaseDir.getAbsolutePath());
+            hostTest.setJarFileName(mJarPath);
             hostTest.setTests(filterTests(mTests, className, methodName));
             return hostTest;
         } else if (mIsSignatureTest) {
@@ -145,7 +144,7 @@
             // points to specialized instrumentation. Eventually this special case for signatureTest
             // can be removed, and it can be treated just like a normal InstrumentationTest
             Log.d(LOG_TAG, String.format("Creating signature test %s", mName));
-            InstrumentationTest instrTest = new InstrumentationTest();
+            InstrumentationApkTest instrTest = new InstrumentationApkTest();
             instrTest.setPackageName(mAppNameSpace);
             instrTest.setRunnerName("android.test.InstrumentationTestRunner");
             instrTest.setClassName(SIGNATURE_TEST_CLASS);
@@ -153,13 +152,7 @@
             // add signature test to list of known tests
             addTest(new TestIdentifier(SIGNATURE_TEST_CLASS, SIGNATURE_TEST_METHOD));
             // mName means 'apk file name' for instrumentation tests
-            File apkFile = new File(testCaseDir, String.format("%s.apk", mName));
-            if (!apkFile.exists()) {
-                Log.w(LOG_TAG, String.format("Could not find apk file %s",
-                        apkFile.getAbsolutePath()));
-                return null;
-            }
-            instrTest.setInstallFile(apkFile);
+            instrTest.addInstallApk(String.format("%s.apk", mName), mAppNameSpace);
             return instrTest;
         } else if (mIsReferenceAppTest) {
             // a reference app test is just a InstrumentationTest with one extra apk to install
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/JarHostTestTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/JarHostTestTest.java
index 9a49b77..dfe4413 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/JarHostTestTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/JarHostTestTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.cts.tradefed.testtype;
 
+import com.android.cts.tradefed.build.StubCtsBuildHelper;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -22,7 +23,6 @@
 
 import org.easymock.EasyMock;
 
-import java.io.File;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -37,6 +37,8 @@
 
     private static final String RUN_NAME = "run";
     private JarHostTest mJarTest;
+    private StubCtsBuildHelper mStubBuildHelper;
+
 
     @Override
     protected void setUp() throws Exception {
@@ -48,6 +50,8 @@
                 return MockTest.class;
             }
         };
+        mStubBuildHelper = new StubCtsBuildHelper();
+        mJarTest.setBuildHelper(mStubBuildHelper);
     }
 
     public static class MockTest extends TestCase {
@@ -80,7 +84,7 @@
         listener.testRunEnded(EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
         mJarTest.setTests(tests);
         mJarTest.setDevice(EasyMock.createMock(ITestDevice.class));
-        mJarTest.setJarFile(new File("fakefile"));
+        mJarTest.setJarFileName("fakefile");
         mJarTest.setRunName(RUN_NAME);
 
         EasyMock.replay(listener);