Automatic sources dropoff on 2020-06-10 18:32:38.095721

The change is generated with prebuilt drop tool.

Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/android/test/ActivityInstrumentationTestCase.java b/android/test/ActivityInstrumentationTestCase.java
new file mode 100644
index 0000000..aca1c16
--- /dev/null
+++ b/android/test/ActivityInstrumentationTestCase.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.app.Activity;
+
+/**
+ * This class provides functional testing of a single activity.  The activity under test will
+ * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
+ * and you will then be able to manipulate your Activity directly.  Most of the work is handled
+ * automatically here by {@link #setUp} and {@link #tearDown}.
+ *
+ * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
+ *
+ * @deprecated new tests should be written using
+ * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+ * configuring the Activity under test
+ */
+@Deprecated
+public abstract class ActivityInstrumentationTestCase<T extends Activity>
+        extends ActivityTestCase {
+    String mPackage;
+    Class<T> mActivityClass;
+    boolean mInitialTouchMode = false;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase} in non-touch mode.
+     *
+     * @param pkg ignored - no longer in use.
+     * @param activityClass The activity to test. This must be a class in the instrumentation
+     * targetPackage specified in the AndroidManifest.xml
+     */
+    public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass) {
+        this(pkg, activityClass, false);
+    }
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase}.
+     *
+     * @param pkg ignored - no longer in use.
+     * @param activityClass The activity to test. This must be a class in the instrumentation
+     * targetPackage specified in the AndroidManifest.xml
+     * @param initialTouchMode true = in touch mode
+     */
+    public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass,
+            boolean initialTouchMode) {
+        mActivityClass = activityClass;
+        mInitialTouchMode = initialTouchMode;
+    }
+
+    @Override
+    public T getActivity() {
+        return (T) super.getActivity();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // set initial touch mode
+        getInstrumentation().setInTouchMode(mInitialTouchMode);
+        final String targetPackageName = getInstrumentation().getTargetContext().getPackageName();
+        setActivity(launchActivity(targetPackageName, mActivityClass, null));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getActivity().finish();
+        setActivity(null);
+
+        // Scrub out members - protects against memory leaks in the case where someone
+        // creates a non-static inner class (thus referencing the test case) and gives it to
+        // someone else to hold onto
+        scrubClass(ActivityInstrumentationTestCase.class);
+
+        super.tearDown();
+    }
+
+    public void testActivityTestCaseSetUpProperly() throws Exception {
+        assertNotNull("activity should be launched successfully", getActivity());
+    }
+}
diff --git a/android/test/ActivityInstrumentationTestCase2.java b/android/test/ActivityInstrumentationTestCase2.java
new file mode 100644
index 0000000..0e61ce7
--- /dev/null
+++ b/android/test/ActivityInstrumentationTestCase2.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.app.Activity;
+import android.content.Intent;
+
+import java.lang.reflect.Method;
+
+/**
+ * This class provides functional testing of a single activity.  The activity under test will
+ * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
+ * and you will then be able to manipulate your Activity directly.
+ *
+ * <p>Other options supported by this test case include:
+ * <ul>
+ * <li>You can run any test method on the UI thread (see {@link android.test.UiThreadTest}).</li>
+ * <li>You can inject custom Intents into your Activity (see
+ * {@link #setActivityIntent(Intent)}).</li>
+ * </ul>
+ *
+ * <p>This class replaces {@link android.test.ActivityInstrumentationTestCase}, which is deprecated.
+ * New tests should be written using this base class.
+ *
+ * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public abstract class ActivityInstrumentationTestCase2<T extends Activity>
+        extends ActivityTestCase {
+    Class<T> mActivityClass;
+    boolean mInitialTouchMode = false;
+    Intent mActivityIntent = null;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2}.
+     *
+     * @param pkg ignored - no longer in use.
+     * @param activityClass The activity to test. This must be a class in the instrumentation
+     * targetPackage specified in the AndroidManifest.xml
+     *
+     * @deprecated use {@link #ActivityInstrumentationTestCase2(Class)} instead
+     */
+    @Deprecated
+    public ActivityInstrumentationTestCase2(String pkg, Class<T> activityClass) {
+        this(activityClass);
+    }
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2}.
+     *
+     * @param activityClass The activity to test. This must be a class in the instrumentation
+     * targetPackage specified in the AndroidManifest.xml
+     */
+    public ActivityInstrumentationTestCase2(Class<T> activityClass) {
+        mActivityClass = activityClass;
+    }
+
+    /**
+     * Get the Activity under test, starting it if necessary.
+     *
+     * For each test method invocation, the Activity will not actually be created until the first
+     * time this method is called.
+     *
+     * <p>If you wish to provide custom setup values to your Activity, you may call
+     * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)}
+     * before your first call to getActivity().  Calling them after your Activity has
+     * started will have no effect.
+     *
+     * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
+     * If your test method is annotated with {@link android.test.UiThreadTest}, then your Activity
+     * will be started automatically just before your test method is run.  You still call this
+     * method in order to get the Activity under test.
+     *
+     * @return the Activity under test
+     */
+    @Override
+    public T getActivity() {
+        Activity a = super.getActivity();
+        if (a == null) {
+            // set initial touch mode
+            getInstrumentation().setInTouchMode(mInitialTouchMode);
+            final String targetPackage = getInstrumentation().getTargetContext().getPackageName();
+            // inject custom intent, if provided
+            if (mActivityIntent == null) {
+                a = launchActivity(targetPackage, mActivityClass, null);
+            } else {
+                a = launchActivityWithIntent(targetPackage, mActivityClass, mActivityIntent);
+            }
+            setActivity(a);
+        }
+        return (T) a;
+    }
+
+    /**
+     * Call this method before the first call to {@link #getActivity} to inject a customized Intent
+     * into the Activity under test.
+     *
+     * <p>If you do not call this, the default intent will be provided.  If you call this after
+     * your Activity has been started, it will have no effect.
+     *
+     * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
+     * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
+     * {@link #setActivityIntent(Intent)} from {@link #setUp()}.
+     *
+     * <p>The default Intent (if this method is not called) is:
+     *  action = {@link Intent#ACTION_MAIN}
+     *  flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+     * All other fields are null or empty.
+     *
+     * @param i The Intent to start the Activity with, or null to reset to the default Intent.
+     */
+    public void setActivityIntent(Intent i) {
+        mActivityIntent = i;
+    }
+
+    /**
+     * Call this method before the first call to {@link #getActivity} to set the initial touch
+     * mode for the Activity under test.
+     *
+     * <p>If you do not call this, the touch mode will be false.  If you call this after
+     * your Activity has been started, it will have no effect.
+     *
+     * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
+     * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
+     * {@link #setActivityInitialTouchMode(boolean)} from {@link #setUp()}.
+     *
+     * @param initialTouchMode true if the Activity should be placed into "touch mode" when started
+     */
+    public void setActivityInitialTouchMode(boolean initialTouchMode) {
+        mInitialTouchMode = initialTouchMode;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mInitialTouchMode = false;
+        mActivityIntent = null;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Finish the Activity off (unless was never launched anyway)
+        Activity a = super.getActivity();
+        if (a != null) {
+            a.finish();
+            setActivity(null);
+        }
+
+        // Scrub out members - protects against memory leaks in the case where someone
+        // creates a non-static inner class (thus referencing the test case) and gives it to
+        // someone else to hold onto
+        scrubClass(ActivityInstrumentationTestCase2.class);
+
+        super.tearDown();
+    }
+
+    /**
+     * Runs the current unit test. If the unit test is annotated with
+     * {@link android.test.UiThreadTest}, force the Activity to be created before switching to
+     * the UI thread.
+     */
+    @Override
+    protected void runTest() throws Throwable {
+        try {
+            Method method = getClass().getMethod(getName(), (Class[]) null);
+            if (method.isAnnotationPresent(UiThreadTest.class)) {
+                getActivity();
+            }
+        } catch (Exception e) {
+            // eat the exception here; super.runTest() will catch it again and handle it properly
+        }
+        super.runTest();
+    }
+
+}
diff --git a/android/test/ActivityTestCase.java b/android/test/ActivityTestCase.java
new file mode 100644
index 0000000..51dd3ef
--- /dev/null
+++ b/android/test/ActivityTestCase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.app.Activity;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * This is common code used to support Activity test cases.  For more useful classes, please see
+ * {@link android.test.ActivityUnitTestCase} and
+ * {@link android.test.ActivityInstrumentationTestCase}.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public abstract class ActivityTestCase extends InstrumentationTestCase {
+
+    /**
+     * The activity that will be set up for use in each test method.
+     */
+    private Activity mActivity;
+
+    /**
+     * @return Returns the activity under test.
+     */
+    protected Activity getActivity() {
+        return mActivity;
+    }
+
+    /**
+     * Set the activity under test.
+     * @param testActivity The activity under test
+     */
+    protected void setActivity(Activity testActivity) {
+        mActivity = testActivity;
+    }
+
+    /**
+     * This function is called by various TestCase implementations, at tearDown() time, in order
+     * to scrub out any class variables.  This protects against memory leaks in the case where a
+     * test case creates a non-static inner class (thus referencing the test case) and gives it to
+     * someone else to hold onto.
+     *
+     * @param testCaseClass The class of the derived TestCase implementation.
+     *
+     * @throws IllegalAccessException
+     */
+    protected void scrubClass(final Class<?> testCaseClass)
+    throws IllegalAccessException {
+        final Field[] fields = getClass().getDeclaredFields();
+        for (Field field : fields) {
+            final Class<?> fieldClass = field.getDeclaringClass();
+            if (testCaseClass.isAssignableFrom(fieldClass) && !field.getType().isPrimitive()
+                    && (field.getModifiers() & Modifier.FINAL) == 0) {
+                try {
+                    field.setAccessible(true);
+                    field.set(this, null);
+                } catch (Exception e) {
+                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
+                }
+
+                if (field.get(this) != null) {
+                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
+                }
+            }
+        }
+    }
+
+
+
+}
diff --git a/android/test/ActivityUnitTestCase.java b/android/test/ActivityUnitTestCase.java
new file mode 100644
index 0000000..a191445
--- /dev/null
+++ b/android/test/ActivityUnitTestCase.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.test.mock.MockApplication;
+import android.view.Window;
+import android.util.Log;
+
+
+
+/**
+ * This class provides isolated testing of a single activity.  The activity under test will
+ * be created with minimal connection to the system infrastructure, and you can inject mocked or
+ * wrappered versions of many of Activity's dependencies.  Most of the work is handled
+ * automatically here by {@link #setUp} and {@link #tearDown}.
+ *
+ * <p>If you prefer a functional test, see {@link android.test.ActivityInstrumentationTestCase}.
+ *
+ * <p>It must be noted that, as a true unit test, your Activity will not be running in the
+ * normal system and will not participate in the normal interactions with other Activities.
+ * The following methods should not be called in this configuration - most of them will throw
+ * exceptions:
+ * <ul>
+ * <li>{@link android.app.Activity#createPendingResult(int, Intent, int)}</li>
+ * <li>{@link android.app.Activity#startActivityIfNeeded(Intent, int)}</li>
+ * <li>{@link android.app.Activity#startActivityFromChild(Activity, Intent, int)}</li>
+ * <li>{@link android.app.Activity#startNextMatchingActivity(Intent)}</li>
+ * <li>{@link android.app.Activity#getCallingActivity()}</li>
+ * <li>{@link android.app.Activity#getCallingPackage()}</li>
+ * <li>{@link android.app.Activity#createPendingResult(int, Intent, int)}</li>
+ * <li>{@link android.app.Activity#getTaskId()}</li>
+ * <li>{@link android.app.Activity#isTaskRoot()}</li>
+ * <li>{@link android.app.Activity#moveTaskToBack(boolean)}</li>
+ * </ul>
+ *
+ * <p>The following methods may be called but will not do anything.  For test purposes, you can use
+ * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to
+ * inspect the parameters that they were called with.
+ * <ul>
+ * <li>{@link android.app.Activity#startActivity(Intent)}</li>
+ * <li>{@link android.app.Activity#startActivityForResult(Intent, int)}</li>
+ * </ul>
+ *
+ * <p>The following methods may be called but will not do anything.  For test purposes, you can use
+ * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the
+ * parameters that they were called with.
+ * <ul>
+ * <li>{@link android.app.Activity#finish()}</li>
+ * <li>{@link android.app.Activity#finishFromChild(Activity child)}</li>
+ * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
+ * </ul>
+ *
+ * @deprecated Write
+ * <a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html">Local Unit Tests</a>
+ * instead.
+ */
+@Deprecated
+public abstract class ActivityUnitTestCase<T extends Activity>
+        extends ActivityTestCase {
+
+    private static final String TAG = "ActivityUnitTestCase";
+    private Class<T> mActivityClass;
+
+    private Context mActivityContext;
+    private Application mApplication;
+    private MockParent mMockParent;
+
+    private boolean mAttached = false;
+    private boolean mCreated = false;
+
+    public ActivityUnitTestCase(Class<T> activityClass) {
+        mActivityClass = activityClass;
+    }
+
+    @Override
+    public T getActivity() {
+        return (T) super.getActivity();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // default value for target context, as a default
+      mActivityContext = getInstrumentation().getTargetContext();
+    }
+
+    /**
+     * Start the activity under test, in the same way as if it was started by
+     * {@link android.content.Context#startActivity Context.startActivity()}, providing the
+     * arguments it supplied.  When you use this method to start the activity, it will automatically
+     * be stopped by {@link #tearDown}.
+     *
+     * <p>This method will call onCreate(), but if you wish to further exercise Activity life
+     * cycle methods, you must call them yourself from your test case.
+     *
+     * <p><i>Do not call from your setUp() method.  You must call this method from each of your
+     * test methods.</i>
+     *
+     * @param intent The Intent as if supplied to {@link android.content.Context#startActivity}.
+     * @param savedInstanceState The instance state, if you are simulating this part of the life
+     * cycle.  Typically null.
+     * @param lastNonConfigurationInstance This Object will be available to the
+     * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.
+     * Typically null.
+     * @return Returns the Activity that was created
+     */
+    protected T startActivity(Intent intent, Bundle savedInstanceState,
+            Object lastNonConfigurationInstance) {
+        assertFalse("Activity already created", mCreated);
+
+        if (!mAttached) {
+            assertNotNull(mActivityClass);
+            setActivity(null);
+            T newActivity = null;
+            try {
+                IBinder token = null;
+                if (mApplication == null) {
+                    setApplication(new MockApplication());
+                }
+                ComponentName cn = new ComponentName(mActivityClass.getPackage().getName(),
+                        mActivityClass.getName());
+                intent.setComponent(cn);
+                ActivityInfo info = new ActivityInfo();
+                CharSequence title = mActivityClass.getName();
+                mMockParent = new MockParent();
+                String id = null;
+
+                newActivity = (T) getInstrumentation().newActivity(mActivityClass, mActivityContext,
+                        token, mApplication, intent, info, title, mMockParent, id,
+                        lastNonConfigurationInstance);
+            } catch (Exception e) {
+                Log.w(TAG, "Catching exception", e);
+                assertNotNull(newActivity);
+            }
+
+            assertNotNull(newActivity);
+            setActivity(newActivity);
+
+            mAttached = true;
+        }
+
+        T result = getActivity();
+        if (result != null) {
+            getInstrumentation().callActivityOnCreate(getActivity(), savedInstanceState);
+            mCreated = true;
+        }
+        return result;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+
+        setActivity(null);
+
+        // Scrub out members - protects against memory leaks in the case where someone
+        // creates a non-static inner class (thus referencing the test case) and gives it to
+        // someone else to hold onto
+        scrubClass(ActivityInstrumentationTestCase.class);
+
+        super.tearDown();
+    }
+
+    /**
+     * Set the application for use during the test.  You must call this function before calling
+     * {@link #startActivity}.  If your test does not call this method,
+     * @param application The Application object that will be injected into the Activity under test.
+     */
+    public void setApplication(Application application) {
+        mApplication = application;
+    }
+
+    /**
+     * If you wish to inject a Mock, Isolated, or otherwise altered context, you can do so
+     * here.  You must call this function before calling {@link #startActivity}.  If you wish to
+     * obtain a real Context, as a building block, use getInstrumentation().getTargetContext().
+     */
+    public void setActivityContext(Context activityContext) {
+        mActivityContext = activityContext;
+    }
+
+    /**
+     * This method will return the value if your Activity under test calls
+     * {@link android.app.Activity#setRequestedOrientation}.
+     */
+    public int getRequestedOrientation() {
+        if (mMockParent != null) {
+            return mMockParent.mRequestedOrientation;
+        }
+        return 0;
+    }
+
+    /**
+     * This method will return the launch intent if your Activity under test calls
+     * {@link android.app.Activity#startActivity(Intent)} or
+     * {@link android.app.Activity#startActivityForResult(Intent, int)}.
+     * @return The Intent provided in the start call, or null if no start call was made.
+     */
+    public Intent getStartedActivityIntent() {
+        if (mMockParent != null) {
+            return mMockParent.mStartedActivityIntent;
+        }
+        return null;
+    }
+
+    /**
+     * This method will return the launch request code if your Activity under test calls
+     * {@link android.app.Activity#startActivityForResult(Intent, int)}.
+     * @return The request code provided in the start call, or -1 if no start call was made.
+     */
+    public int getStartedActivityRequest() {
+        if (mMockParent != null) {
+            return mMockParent.mStartedActivityRequest;
+        }
+        return 0;
+    }
+
+    /**
+     * This method will notify you if the Activity under test called
+     * {@link android.app.Activity#finish()},
+     * {@link android.app.Activity#finishFromChild(Activity)}, or
+     * {@link android.app.Activity#finishActivity(int)}.
+     * @return Returns true if one of the listed finish methods was called.
+     */
+    public boolean isFinishCalled() {
+        if (mMockParent != null) {
+            return mMockParent.mFinished;
+        }
+        return false;
+    }
+
+    /**
+     * This method will return the request code if the Activity under test called
+     * {@link android.app.Activity#finishActivity(int)}.
+     * @return The request code provided in the start call, or -1 if no finish call was made.
+     */
+    public int getFinishedActivityRequest() {
+        if (mMockParent != null) {
+            return mMockParent.mFinishedActivityRequest;
+        }
+        return 0;
+    }
+
+    /**
+     * This mock Activity represents the "parent" activity.  By injecting this, we allow the user
+     * to call a few more Activity methods, including:
+     * <ul>
+     * <li>{@link android.app.Activity#getRequestedOrientation()}</li>
+     * <li>{@link android.app.Activity#setRequestedOrientation(int)}</li>
+     * <li>{@link android.app.Activity#finish()}</li>
+     * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
+     * <li>{@link android.app.Activity#finishFromChild(Activity child)}</li>
+     * </ul>
+     *
+     * TODO: Make this overrideable, and the unit test can look for calls to other methods
+     */
+    private static class MockParent extends Activity {
+
+        public int mRequestedOrientation = 0;
+        public Intent mStartedActivityIntent = null;
+        public int mStartedActivityRequest = -1;
+        public boolean mFinished = false;
+        public int mFinishedActivityRequest = -1;
+
+        /**
+         * Implementing in the parent allows the user to call this function on the tested activity.
+         */
+        @Override
+        public void setRequestedOrientation(int requestedOrientation) {
+            mRequestedOrientation = requestedOrientation;
+        }
+
+        /**
+         * Implementing in the parent allows the user to call this function on the tested activity.
+         */
+        @Override
+        public int getRequestedOrientation() {
+            return mRequestedOrientation;
+        }
+
+        /**
+         * By returning null here, we inhibit the creation of any "container" for the window.
+         */
+        @Override
+        public Window getWindow() {
+            return null;
+        }
+
+        /**
+         * By defining this in the parent, we allow the tested activity to call
+         * <ul>
+         * <li>{@link android.app.Activity#startActivity(Intent)}</li>
+         * <li>{@link android.app.Activity#startActivityForResult(Intent, int)}</li>
+         * </ul>
+         */
+        @Override
+        public void startActivityFromChild(Activity child, Intent intent, int requestCode) {
+            mStartedActivityIntent = intent;
+            mStartedActivityRequest = requestCode;
+        }
+
+        /**
+         * By defining this in the parent, we allow the tested activity to call
+         * <ul>
+         * <li>{@link android.app.Activity#finish()}</li>
+         * <li>{@link android.app.Activity#finishFromChild(Activity child)}</li>
+         * </ul>
+         */
+        @Override
+        public void finishFromChild(Activity child) {
+            mFinished = true;
+        }
+
+        /**
+         * By defining this in the parent, we allow the tested activity to call
+         * <ul>
+         * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
+         * </ul>
+         */
+        @Override
+        public void finishActivityFromChild(Activity child, int requestCode) {
+            mFinished = true;
+            mFinishedActivityRequest = requestCode;
+        }
+    }
+}
diff --git a/android/test/AndroidTestCase.java b/android/test/AndroidTestCase.java
new file mode 100644
index 0000000..fcb8d43
--- /dev/null
+++ b/android/test/AndroidTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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.test;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+
+import junit.framework.TestCase;
+
+/**
+ * @deprecated Stub only
+ */
+@SuppressWarnings({ "unchecked", "deprecation", "all" })
+@Deprecated
+public class AndroidTestCase extends TestCase {
+
+    /**
+     * Stub only
+     */
+    @UnsupportedAppUsage
+    public void setTestContext(Context context) {
+        throw new RuntimeException("Stub!");
+    }
+
+    /**
+     * Stub only
+     */
+    @UnsupportedAppUsage
+    public Context getTestContext() {
+        throw new RuntimeException("Stub!");
+    }
+}
diff --git a/android/test/AndroidTestRunner.java b/android/test/AndroidTestRunner.java
new file mode 100644
index 0000000..f898516
--- /dev/null
+++ b/android/test/AndroidTestRunner.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.app.Instrumentation;
+import android.content.Context;
+
+import java.util.ArrayList;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.runner.BaseTestRunner;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+/**
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class AndroidTestRunner extends BaseTestRunner {
+
+    private TestResult mTestResult;
+    private String mTestClassName;
+    private List<TestCase> mTestCases;
+    private Context mContext;
+    private boolean mSkipExecution = false;
+
+    private List<TestListener> mTestListeners = new ArrayList<>();
+    private Instrumentation mInstrumentation;
+
+    @SuppressWarnings("unchecked")
+    public void setTestClassName(String testClassName, String testMethodName) {
+        Class testClass = loadTestClass(testClassName);
+
+        if (shouldRunSingleTestMethod(testMethodName, testClass)) {
+            TestCase testCase = buildSingleTestMethod(testClass, testMethodName);
+            mTestCases = new ArrayList<>();
+            mTestCases.add(testCase);
+            mTestClassName = testClass.getSimpleName();
+        } else {
+            setTest(getTest(testClass), testClass);
+        }
+    }
+
+    public void setTest(Test test) {
+        setTest(test, test.getClass());
+    }
+
+    private void setTest(Test test, Class<? extends Test> testClass) {
+        mTestCases = (List<TestCase>) TestCaseUtil.getTests(test, true);
+        if (TestSuite.class.isAssignableFrom(testClass)) {
+            mTestClassName = TestCaseUtil.getTestName(test);
+        } else {
+            mTestClassName = testClass.getSimpleName();
+        }
+    }
+
+    public void clearTestListeners() {
+        mTestListeners.clear();
+    }
+
+    public void addTestListener(TestListener testListener) {
+        if (testListener != null) {
+            mTestListeners.add(testListener);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Class<? extends Test> loadTestClass(String testClassName) {
+        try {
+            return (Class<? extends Test>) mContext.getClassLoader().loadClass(testClassName);
+        } catch (ClassNotFoundException e) {
+            runFailed("Could not find test class. Class: " + testClassName);
+        }
+        return null;
+    }
+
+    private TestCase buildSingleTestMethod(Class testClass, String testMethodName) {
+        try {
+            Constructor c = testClass.getConstructor();
+            return newSingleTestMethod(testClass, testMethodName, c);
+        } catch (NoSuchMethodException e) {
+        }
+
+        try {
+            Constructor c = testClass.getConstructor(String.class);
+            return newSingleTestMethod(testClass, testMethodName, c, testMethodName);
+        } catch (NoSuchMethodException e) {
+        }
+
+        return null;
+    }
+
+    private TestCase newSingleTestMethod(Class testClass, String testMethodName,
+            Constructor constructor, Object... args) {
+        try {
+            TestCase testCase = (TestCase) constructor.newInstance(args);
+            testCase.setName(testMethodName);
+            return testCase;
+        } catch (IllegalAccessException e) {
+            runFailed("Could not access test class. Class: " + testClass.getName());
+        } catch (InstantiationException e) {
+            runFailed("Could not instantiate test class. Class: " + testClass.getName());
+        } catch (IllegalArgumentException e) {
+            runFailed("Illegal argument passed to constructor. Class: " + testClass.getName());
+        } catch (InvocationTargetException e) {
+            runFailed("Constructor thew an exception. Class: " + testClass.getName());
+        }
+        return null;
+    }
+
+    private boolean shouldRunSingleTestMethod(String testMethodName,
+            Class<? extends Test> testClass) {
+        return testMethodName != null && TestCase.class.isAssignableFrom(testClass);
+    }
+
+    private Test getTest(Class clazz) {
+        if (TestSuiteProvider.class.isAssignableFrom(clazz)) {
+            try {
+                TestSuiteProvider testSuiteProvider =
+                        (TestSuiteProvider) clazz.getConstructor().newInstance();
+                return testSuiteProvider.getTestSuite();
+            } catch (InstantiationException e) {
+                runFailed("Could not instantiate test suite provider. Class: " + clazz.getName());
+            } catch (IllegalAccessException e) {
+                runFailed("Illegal access of test suite provider. Class: " + clazz.getName());
+            } catch (InvocationTargetException e) {
+                runFailed("Invocation exception test suite provider. Class: " + clazz.getName());
+            } catch (NoSuchMethodException e) {
+                runFailed("No such method on test suite provider. Class: " + clazz.getName());
+            }
+        }
+        return getTest(clazz.getName());
+    }
+
+    protected TestResult createTestResult() {
+        if (mSkipExecution) {
+            return new NoExecTestResult();
+        }
+        return new TestResult();
+    }
+
+    void setSkipExecution(boolean skip) {
+        mSkipExecution = skip;
+    }
+
+    public List<TestCase> getTestCases() {
+        return mTestCases;
+    }
+
+    public String getTestClassName() {
+        return mTestClassName;
+    }
+
+    public TestResult getTestResult() {
+        return mTestResult;
+    }
+
+    public void runTest() {
+        runTest(createTestResult());
+    }
+
+    public void runTest(TestResult testResult) {
+        mTestResult = testResult;
+
+        for (TestListener testListener : mTestListeners) {
+            mTestResult.addListener(testListener);
+        }
+
+        Context testContext = mInstrumentation == null ? mContext : mInstrumentation.getContext();
+        for (TestCase testCase : mTestCases) {
+            setContextIfAndroidTestCase(testCase, mContext, testContext);
+            setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
+            testCase.run(mTestResult);
+        }
+    }
+
+    private void setContextIfAndroidTestCase(Test test, Context context, Context testContext) {
+        if (AndroidTestCase.class.isAssignableFrom(test.getClass())) {
+            ((AndroidTestCase) test).setContext(context);
+            ((AndroidTestCase) test).setTestContext(testContext);
+        }
+    }
+
+    public void setContext(Context context) {
+        mContext = context;
+    }
+
+    private void setInstrumentationIfInstrumentationTestCase(
+            Test test, Instrumentation instrumentation) {
+        if (InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
+            ((InstrumentationTestCase) test).injectInstrumentation(instrumentation);
+        }
+    }
+
+    public void setInstrumentation(Instrumentation instrumentation) {
+        mInstrumentation = instrumentation;
+    }
+
+    /**
+     * @deprecated Incorrect spelling,
+     * use {@link #setInstrumentation(android.app.Instrumentation)} instead.
+     */
+    @Deprecated
+    public void setInstrumentaiton(Instrumentation instrumentation) {
+        setInstrumentation(instrumentation);
+    }
+
+    @Override
+    protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+        return mContext.getClassLoader().loadClass(suiteClassName);
+    }
+
+    public void testStarted(String testName) {
+    }
+
+    public void testEnded(String testName) {
+    }
+
+    public void testFailed(int status, Test test, Throwable t) {
+    }
+
+    protected void runFailed(String message) {
+        throw new RuntimeException(message);
+    }
+}
diff --git a/android/test/ApplicationTestCase.java b/android/test/ApplicationTestCase.java
new file mode 100644
index 0000000..4d73f53
--- /dev/null
+++ b/android/test/ApplicationTestCase.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.app.Application;
+import android.app.Instrumentation;
+import android.content.Context;
+
+/**
+ * This test case provides a framework in which you can test Application classes in
+ * a controlled environment.  It provides basic support for the lifecycle of a
+ * Application, and hooks by which you can inject various dependencies and control
+ * the environment in which your Application is tested.
+ *
+ * <p><b>Lifecycle Support.</b>
+ * Every Application is designed to be accessed within a specific sequence of
+ * method calls (see {@link android.app.Application} for more details).
+ * In order to support the lifecycle of a Application, this test case will make the
+ * following calls at the following times.
+ *
+ * <ul><li>The test case will not call onCreate() until your test calls
+ * {@link #createApplication()}.  This gives you a chance
+ * to set up or adjust any additional framework or test logic before
+ * onCreate().</li>
+ * <li>After your test completes, the test case {@link #tearDown} method is
+ * automatically called, and it will stop & destroy your application by calling its
+ * onDestroy() method.</li>
+ * </ul>
+ *
+ * <p><b>Dependency Injection.</b>
+ * Every Application has one inherent dependency, the {@link android.content.Context Context} in
+ * which it runs.
+ * This framework allows you to inject a modified, mock, or isolated replacement for this
+ * dependencies, and thus perform a true unit test.
+ *
+ * <p>If simply run your tests as-is, your Application will be injected with a fully-functional
+ * Context.
+ * You can create and inject alternative types of Contexts by calling
+ * {@link AndroidTestCase#setContext(Context) setContext()}.  You must do this <i>before</i> calling
+ * {@link #createApplication()}.  The test framework provides a
+ * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext},
+ * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and
+ * {@link android.content.ContextWrapper ContextWrapper}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public abstract class ApplicationTestCase<T extends Application> extends AndroidTestCase {
+
+    Class<T> mApplicationClass;
+
+    private Context mSystemContext;
+
+    public ApplicationTestCase(Class<T> applicationClass) {
+        mApplicationClass = applicationClass;
+    }
+
+    private T mApplication;
+    private boolean mAttached = false;
+    private boolean mCreated = false;
+
+    /**
+     * @return Returns the actual Application under test.
+     */
+    public T getApplication() {
+        return mApplication;
+    }
+
+    /**
+     * This will do the work to instantiate the Application under test.  After this, your test
+     * code must also start and stop the Application.
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // get the real context, before the individual tests have a chance to muck with it
+        mSystemContext = getContext();
+    }
+
+    /**
+     * Load and attach the application under test.
+     */
+    private void setupApplication() {
+        mApplication = null;
+        try {
+            mApplication = (T) Instrumentation.newApplication(mApplicationClass, getContext());
+        } catch (Exception e) {
+            assertNotNull(mApplication);
+        }
+        mAttached = true;
+    }
+
+    /**
+     * Start the Application under test, in the same way as if it was started by the system.
+     * If you use this method to start the Application, it will automatically
+     * be stopped by {@link #tearDown}.  If you wish to inject a specialized Context for your
+     * test, by calling {@link AndroidTestCase#setContext(Context) setContext()},
+     * you must do so  before calling this method.
+     */
+    final protected void createApplication() {
+        assertFalse(mCreated);
+
+        if (!mAttached) {
+            setupApplication();
+        }
+        assertNotNull(mApplication);
+
+        mApplication.onCreate();
+        mCreated = true;
+    }
+
+    /**
+     * This will make the necessary calls to terminate the Application under test (it will
+     * call onTerminate().  Ordinarily this will be called automatically (by {@link #tearDown}, but
+     * you can call it directly from your test in order to check for proper shutdown behaviors.
+     */
+    final protected void terminateApplication() {
+        if (mCreated) {
+            mApplication.onTerminate();
+        }
+    }
+
+    /**
+     * Shuts down the Application under test.  Also makes sure all resources are cleaned up and
+     * garbage collected before moving on to the next
+     * test.  Subclasses that override this method should make sure they call super.tearDown()
+     * at the end of the overriding method.
+     *
+     * @throws Exception
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        terminateApplication();
+        mApplication = null;
+
+        // Scrub out members - protects against memory leaks in the case where someone
+        // creates a non-static inner class (thus referencing the test case) and gives it to
+        // someone else to hold onto
+        scrubClass(ApplicationTestCase.class);
+
+        super.tearDown();
+    }
+
+    /**
+     * Return a real (not mocked or instrumented) system Context that can be used when generating
+     * Mock or other Context objects for your Application under test.
+     *
+     * @return Returns a reference to a normal Context.
+     */
+    public Context getSystemContext() {
+        return mSystemContext;
+    }
+
+    /**
+     * This test simply confirms that the Application class can be instantiated properly.
+     *
+     * @throws Exception
+     */
+    final public void testApplicationTestCaseSetUpProperly() throws Exception {
+        setupApplication();
+        assertNotNull("Application class could not be instantiated successfully", mApplication);
+    }
+}
diff --git a/android/test/AssertionFailedError.java b/android/test/AssertionFailedError.java
new file mode 100644
index 0000000..fc3e98e
--- /dev/null
+++ b/android/test/AssertionFailedError.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+/**
+ * Thrown when an assertion failed.
+ *
+ * @deprecated use junit.framework.AssertionFailedError
+ */
+@Deprecated
+public class AssertionFailedError extends Error {
+
+    /**
+     * It is more typical to call {@link #AssertionFailedError(String)}.
+     */
+    public AssertionFailedError() {
+    }
+
+    public AssertionFailedError(String errorMessage) {
+        super(errorMessage);
+    }
+}
diff --git a/android/test/ClassPathPackageInfoSource.java b/android/test/ClassPathPackageInfoSource.java
new file mode 100644
index 0000000..755b540
--- /dev/null
+++ b/android/test/ClassPathPackageInfoSource.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.util.Log;
+import dalvik.system.DexFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+/**
+ * Generate {@link ClassPathPackageInfo}s by scanning apk paths.
+ *
+ * {@hide} Not needed for 1.0 SDK.
+ */
+@Deprecated
+public class ClassPathPackageInfoSource {
+
+    private static final ClassLoader CLASS_LOADER
+            = ClassPathPackageInfoSource.class.getClassLoader();
+
+    private static String[] apkPaths;
+
+    private static ClassPathPackageInfoSource classPathSource;
+
+    private final SimpleCache<String, ClassPathPackageInfo> cache =
+            new SimpleCache<String, ClassPathPackageInfo>() {
+                @Override
+                protected ClassPathPackageInfo load(String pkgName) {
+                    return createPackageInfo(pkgName);
+                }
+            };
+
+    // The class path of the running application
+    private final String[] classPath;
+
+    private final ClassLoader classLoader;
+
+    private ClassPathPackageInfoSource(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+        classPath = getClassPath();
+    }
+
+    static void setApkPaths(String[] apkPaths) {
+        ClassPathPackageInfoSource.apkPaths = apkPaths;
+    }
+
+    public static ClassPathPackageInfoSource forClassPath(ClassLoader classLoader) {
+        if (classPathSource == null) {
+            classPathSource = new ClassPathPackageInfoSource(classLoader);
+        }
+        return classPathSource;
+    }
+
+    public Set<Class<?>> getTopLevelClassesRecursive(String packageName) {
+        ClassPathPackageInfo packageInfo = cache.get(packageName);
+        return packageInfo.getTopLevelClassesRecursive();
+    }
+
+    private ClassPathPackageInfo createPackageInfo(String packageName) {
+        Set<String> subpackageNames = new TreeSet<String>();
+        Set<String> classNames = new TreeSet<String>();
+        Set<Class<?>> topLevelClasses = new HashSet<>();
+        findClasses(packageName, classNames, subpackageNames);
+        for (String className : classNames) {
+            if (className.endsWith(".R") || className.endsWith(".Manifest")) {
+                // Don't try to load classes that are generated. They usually aren't in test apks.
+                continue;
+            }
+
+            try {
+                // We get errors in the emulator if we don't use the caller's class loader.
+                topLevelClasses.add(Class.forName(className, false,
+                        (classLoader != null) ? classLoader : CLASS_LOADER));
+            } catch (ClassNotFoundException | NoClassDefFoundError e) {
+                // Should not happen unless there is a generated class that is not included in
+                // the .apk.
+                Log.w("ClassPathPackageInfoSource", "Cannot load class. "
+                        + "Make sure it is in your apk. Class name: '" + className
+                        + "'. Message: " + e.getMessage(), e);
+            }
+        }
+        return new ClassPathPackageInfo(packageName, subpackageNames,
+                topLevelClasses);
+    }
+
+    /**
+     * Finds all classes and sub packages that are below the packageName and
+     * add them to the respective sets. Searches the package on the whole class
+     * path.
+     */
+    private void findClasses(String packageName, Set<String> classNames,
+            Set<String> subpackageNames) {
+        for (String entryName : classPath) {
+            File classPathEntry = new File(entryName);
+
+            // Forge may not have brought over every item in the classpath. Be
+            // polite and ignore missing entries.
+            if (classPathEntry.exists()) {
+                try {
+                    if (entryName.endsWith(".apk")) {
+                        findClassesInApk(entryName, packageName, classNames, subpackageNames);
+                    } else {
+                        // scan the directories that contain apk files.
+                        for (String apkPath : apkPaths) {
+                            File file = new File(apkPath);
+                            scanForApkFiles(file, packageName, classNames, subpackageNames);
+                        }
+                    }
+                } catch (IOException e) {
+                    throw new AssertionError("Can't read classpath entry " +
+                            entryName + ": " + e.getMessage());
+                }
+            }
+        }
+    }
+
+    private void scanForApkFiles(File source, String packageName,
+            Set<String> classNames, Set<String> subpackageNames) throws IOException {
+        if (source.getPath().endsWith(".apk")) {
+            findClassesInApk(source.getPath(), packageName, classNames, subpackageNames);
+        } else {
+            File[] files = source.listFiles();
+            if (files != null) {
+                for (File file : files) {
+                    scanForApkFiles(file, packageName, classNames, subpackageNames);
+                }
+            }
+        }
+    }
+
+    /**
+     * Finds all classes and sub packages that are below the packageName and
+     * add them to the respective sets. Searches the package in a single apk file.
+     */
+    private void findClassesInApk(String apkPath, String packageName,
+            Set<String> classNames, Set<String> subpackageNames)
+            throws IOException {
+
+        DexFile dexFile = null;
+        try {
+            dexFile = new DexFile(apkPath);
+            Enumeration<String> apkClassNames = dexFile.entries();
+            while (apkClassNames.hasMoreElements()) {
+                String className = apkClassNames.nextElement();
+
+                if (className.startsWith(packageName)) {
+                    String subPackageName = packageName;
+                    int lastPackageSeparator = className.lastIndexOf('.');
+                    if (lastPackageSeparator > 0) {
+                        subPackageName = className.substring(0, lastPackageSeparator);
+                    }
+                    if (subPackageName.length() > packageName.length()) {
+                        subpackageNames.add(subPackageName);
+                    } else if (isToplevelClass(className)) {
+                        classNames.add(className);
+                    }
+                }
+            }
+        } catch (IOException e) {
+            if (false) {
+                Log.w("ClassPathPackageInfoSource",
+                        "Error finding classes at apk path: " + apkPath, e);
+            }
+        } finally {
+            if (dexFile != null) {
+                // Todo: figure out why closing causes a dalvik error resulting in vm shutdown.
+//                dexFile.close();
+            }
+        }
+    }
+
+    /**
+     * Checks if a given file name represents a toplevel class.
+     */
+    private static boolean isToplevelClass(String fileName) {
+        return fileName.indexOf('$') < 0;
+    }
+
+    /**
+     * Gets the class path from the System Property "java.class.path" and splits
+     * it up into the individual elements.
+     */
+    private static String[] getClassPath() {
+        String classPath = System.getProperty("java.class.path");
+        String separator = System.getProperty("path.separator", ":");
+        return classPath.split(Pattern.quote(separator));
+    }
+
+    /**
+     * The Package object doesn't allow you to iterate over the contained
+     * classes and subpackages of that package.  This is a version that does.
+     */
+    private class ClassPathPackageInfo {
+
+        private final String packageName;
+        private final Set<String> subpackageNames;
+        private final Set<Class<?>> topLevelClasses;
+
+        private ClassPathPackageInfo(String packageName,
+                Set<String> subpackageNames, Set<Class<?>> topLevelClasses) {
+            this.packageName = packageName;
+            this.subpackageNames = Collections.unmodifiableSet(subpackageNames);
+            this.topLevelClasses = Collections.unmodifiableSet(topLevelClasses);
+        }
+
+        private Set<ClassPathPackageInfo> getSubpackages() {
+            Set<ClassPathPackageInfo> info = new HashSet<>();
+            for (String name : subpackageNames) {
+                info.add(cache.get(name));
+            }
+            return info;
+        }
+
+        private Set<Class<?>> getTopLevelClassesRecursive() {
+            Set<Class<?>> set = new HashSet<>();
+            addTopLevelClassesTo(set);
+            return set;
+        }
+
+        private void addTopLevelClassesTo(Set<Class<?>> set) {
+            set.addAll(topLevelClasses);
+            for (ClassPathPackageInfo info : getSubpackages()) {
+                info.addTopLevelClassesTo(set);
+            }
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ClassPathPackageInfo) {
+                ClassPathPackageInfo that = (ClassPathPackageInfo) obj;
+                return (this.packageName).equals(that.packageName);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return packageName.hashCode();
+        }
+    }
+}
diff --git a/android/test/ComparisonFailure.java b/android/test/ComparisonFailure.java
new file mode 100644
index 0000000..d86b700
--- /dev/null
+++ b/android/test/ComparisonFailure.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+/**
+ * Thrown when an assert equals for Strings failed.
+ * 
+ * @deprecated use org.junit.ComparisonFailure
+ */
+@Deprecated
+public class ComparisonFailure extends AssertionFailedError {
+    private junit.framework.ComparisonFailure mComparison;
+
+    public ComparisonFailure(String message, String expected, String actual) {
+        mComparison = new junit.framework.ComparisonFailure(message, expected, actual);
+    }
+
+    public String getMessage() {
+        return mComparison.getMessage();
+    }
+}
diff --git a/android/test/FlakyTest.java b/android/test/FlakyTest.java
new file mode 100644
index 0000000..4e5c4e3
--- /dev/null
+++ b/android/test/FlakyTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * This annotation can be used on an {@link android.test.InstrumentationTestCase}'s
+ * test methods. When the annotation is present, the test method is re-executed if
+ * the test fails. The total number of executions is specified by the tolerance and
+ * defaults to 1.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/FlakyTest.html">
+ * FlakyTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FlakyTest {
+    /**
+     * Indicates how many times a test can run and fail before being reported
+     * as a failed test. If the tolerance factor is less than 1, the test runs
+     * only once.
+     *
+     * @return The total number of allowed run, the default is 1.
+     */
+    int tolerance() default 1;
+}
diff --git a/android/test/InstrumentationTestCase.java b/android/test/InstrumentationTestCase.java
new file mode 100644
index 0000000..a48a56c
--- /dev/null
+++ b/android/test/InstrumentationTestCase.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.test;
+
+import android.compat.annotation.UnsupportedAppUsage;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Method;
+
+/**
+ * @deprecated Stub only
+ */
+@SuppressWarnings({ "unchecked", "deprecation", "all" })
+@Deprecated
+public class InstrumentationTestCase extends TestCase {
+
+    /**
+     * Stub only
+     */
+    @UnsupportedAppUsage
+    private void runMethod(Method runMethod, int tolerance) throws Throwable {
+        throw new RuntimeException("Stub!");
+    }
+}
diff --git a/android/test/InstrumentationTestRunner.java b/android/test/InstrumentationTestRunner.java
new file mode 100644
index 0000000..b2582c1
--- /dev/null
+++ b/android/test/InstrumentationTestRunner.java
@@ -0,0 +1,854 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.util.Predicate;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Looper;
+import android.test.suitebuilder.TestMethod;
+import android.test.suitebuilder.TestPredicates;
+import android.test.suitebuilder.TestSuiteBuilder;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.runner.BaseTestRunner;
+import junit.textui.ResultPrinter;
+
+import static android.test.suitebuilder.TestPredicates.hasAnnotation;
+
+/**
+ * An {@link Instrumentation} that runs various types of {@link junit.framework.TestCase}s against
+ * an Android package (application).
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about application testing, read the
+ * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
+ * </div>
+ *
+ * <h3>Typical Usage</h3>
+ * <ol>
+ * <li>Write {@link junit.framework.TestCase}s that perform unit, functional, or performance tests
+ * against the classes in your package.  Typically these are subclassed from:
+ *   <ul><li>{@link android.test.ActivityInstrumentationTestCase2}</li>
+ *   <li>{@link android.test.ActivityUnitTestCase}</li>
+ *   <li>{@link android.test.AndroidTestCase}</li>
+ *   <li>{@link android.test.ApplicationTestCase}</li>
+ *   <li>{@link android.test.InstrumentationTestCase}</li>
+ *   <li>{@link android.test.ProviderTestCase}</li>
+ *   <li>{@link android.test.ServiceTestCase}</li>
+ *   <li>{@link android.test.SingleLaunchActivityTestCase}</li></ul>
+ * <li>Set the <code>android:targetPackage</code> attribute of the <code>&lt;instrumentation&gt;</code>
+ * element in the test package's manifest. You should set the attribute value
+ * to the package name of the target application under test.
+ * <li>Run the instrumentation using "adb shell am instrument -w",
+ * with no optional arguments, to run all tests (except performance tests).
+ * <li>Run the instrumentation using "adb shell am instrument -w",
+ * with the argument '-e func true' to run all functional tests. These are tests that derive from
+ * {@link android.test.InstrumentationTestCase}.
+ * <li>Run the instrumentation using "adb shell am instrument -w",
+ * with the argument '-e unit true' to run all unit tests. These are tests that <i>do not</i>derive
+ * from {@link android.test.InstrumentationTestCase} (and are not performance tests).
+ * <li>Run the instrumentation using "adb shell am instrument -w",
+ * with the argument '-e class' set to run an individual {@link junit.framework.TestCase}.
+ * </ol>
+ * <p/>
+ * <b>Running all tests:</b> adb shell am instrument -w
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Running all small tests:</b> adb shell am instrument -w
+ * -e size small
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Running all medium tests:</b> adb shell am instrument -w
+ * -e size medium
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Running all large tests:</b> adb shell am instrument -w
+ * -e size large
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Filter test run to tests with given annotation:</b> adb shell am instrument -w
+ * -e annotation com.android.foo.MyAnnotation
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * If used with other options, the resulting test run will contain the union of the two options.
+ * e.g. "-e size large -e annotation com.android.foo.MyAnnotation" will run only tests with both
+ * the {@link LargeTest} and "com.android.foo.MyAnnotation" annotations.
+ * <p/>
+ * <b>Filter test run to tests <i>without</i> given annotation:</b> adb shell am instrument -w
+ * -e notAnnotation com.android.foo.MyAnnotation
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Running a single testcase:</b> adb shell am instrument -w
+ * -e class com.android.foo.FooTest
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Running a single test:</b> adb shell am instrument -w
+ * -e class com.android.foo.FooTest#testFoo
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Running multiple tests:</b> adb shell am instrument -w
+ * -e class com.android.foo.FooTest,com.android.foo.TooTest
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Running all tests in a java package:</b> adb shell am instrument -w
+ * -e package com.android.foo.subpkg
+ *  com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>Including performance tests:</b> adb shell am instrument -w
+ * -e perf true
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * <b>To debug your tests, set a break point in your code and pass:</b>
+ * -e debug true
+ * <p/>
+ * <b>To run in 'log only' mode</b>
+ * -e log true
+ * This option will load and iterate through all test classes and methods, but will bypass actual
+ * test execution. Useful for quickly obtaining info on the tests to be executed by an
+ * instrumentation command.
+ * <p/>
+ * <b>To generate EMMA code coverage:</b>
+ * -e coverage true
+ * Note: this requires an emma instrumented build. By default, the code coverage results file
+ * will be saved in a /data/<app>/coverage.ec file, unless overridden by coverageFile flag (see
+ * below)
+ * <p/>
+ * <b> To specify EMMA code coverage results file path:</b>
+ * -e coverageFile /sdcard/myFile.ec
+ * <br/>
+ * in addition to the other arguments.
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+
+/* (not JavaDoc)
+ * Although not necessary in most case, another way to use this class is to extend it and have the
+ * derived class return the desired test suite from the {@link #getTestSuite()} method. The test
+ * suite returned from this method will be used if no target class is defined in the meta-data or
+ * command line argument parameters. If a derived class is used it needs to be added as an
+ * instrumentation to the AndroidManifest.xml and the command to run it would look like:
+ * <p/>
+ * adb shell am instrument -w com.android.foo/<i>com.android.FooInstrumentationTestRunner</i>
+ * <p/>
+ * Where <i>com.android.FooInstrumentationTestRunner</i> is the derived class.
+ *
+ * This model is used by many existing app tests, but can probably be deprecated.
+ */
+@Deprecated
+public class InstrumentationTestRunner extends Instrumentation implements TestSuiteProvider {
+
+    /** @hide */
+    static final String ARGUMENT_TEST_CLASS = "class";
+    /** @hide */
+    private static final String ARGUMENT_TEST_PACKAGE = "package";
+    /** @hide */
+    private static final String ARGUMENT_TEST_SIZE_PREDICATE = "size";
+    /** @hide */
+    static final String ARGUMENT_DELAY_MSEC = "delay_msec";
+
+    private static final String SMALL_SUITE = "small";
+    private static final String MEDIUM_SUITE = "medium";
+    private static final String LARGE_SUITE = "large";
+
+    private static final String ARGUMENT_LOG_ONLY = "log";
+    /** @hide */
+    static final String ARGUMENT_ANNOTATION = "annotation";
+    /** @hide */
+    static final String ARGUMENT_NOT_ANNOTATION = "notAnnotation";
+
+    private static final Predicate<TestMethod> SELECT_SMALL = hasAnnotation(SmallTest.class);
+
+    private static final Predicate<TestMethod> SELECT_MEDIUM = hasAnnotation(MediumTest.class);
+
+    private static final Predicate<TestMethod> SELECT_LARGE = hasAnnotation(LargeTest.class);
+
+    /**
+     * This constant defines the maximum allowed runtime (in ms) for a test included in the "small"
+     * suite. It is used to make an educated guess at what suite an unlabeled test belongs.
+     */
+    private static final float SMALL_SUITE_MAX_RUNTIME = 100;
+
+    /**
+     * This constant defines the maximum allowed runtime (in ms) for a test included in the
+     * "medium" suite. It is used to make an educated guess at what suite an unlabeled test belongs.
+     */
+    private static final float MEDIUM_SUITE_MAX_RUNTIME = 1000;
+
+    /*
+     * The following keys are used in the status bundle to provide structured reports to
+     * an IInstrumentationWatcher.
+     */
+
+    /**
+     * This value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER},
+     * identifies InstrumentationTestRunner as the source of the report.  This is sent with all
+     * status messages.
+     */
+    public static final String REPORT_VALUE_ID = "InstrumentationTestRunner";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * identifies the total number of tests that are being run.  This is sent with all status
+     * messages.
+     */
+    public static final String REPORT_KEY_NUM_TOTAL = "numtests";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * identifies the sequence number of the current test.  This is sent with any status message
+     * describing a specific test being started or completed.
+     */
+    public static final String REPORT_KEY_NUM_CURRENT = "current";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * identifies the name of the current test class.  This is sent with any status message
+     * describing a specific test being started or completed.
+     */
+    public static final String REPORT_KEY_NAME_CLASS = "class";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * identifies the name of the current test.  This is sent with any status message
+     * describing a specific test being started or completed.
+     */
+    public static final String REPORT_KEY_NAME_TEST = "test";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * reports the run time in seconds of the current test.
+     */
+    private static final String REPORT_KEY_RUN_TIME = "runtime";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * reports the number of total iterations of the current test.
+     */
+    private static final String REPORT_KEY_NUM_ITERATIONS = "numiterations";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * reports the guessed suite assignment for the current test.
+     */
+    private static final String REPORT_KEY_SUITE_ASSIGNMENT = "suiteassignment";
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * identifies the path to the generated code coverage file.
+     */
+    private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath";
+
+    /**
+     * The test is starting.
+     */
+    public static final int REPORT_VALUE_RESULT_START = 1;
+    /**
+     * The test completed successfully.
+     */
+    public static final int REPORT_VALUE_RESULT_OK = 0;
+    /**
+     * The test completed with an error.
+     */
+    public static final int REPORT_VALUE_RESULT_ERROR = -1;
+    /**
+     * The test completed with a failure.
+     */
+    public static final int REPORT_VALUE_RESULT_FAILURE = -2;
+    /**
+     * If included in the status bundle sent to an IInstrumentationWatcher, this key
+     * identifies a stack trace describing an error or failure.  This is sent with any status
+     * message describing a specific test being completed.
+     */
+    public static final String REPORT_KEY_STACK = "stack";
+
+    // Default file name for code coverage
+    private static final String DEFAULT_COVERAGE_FILE_NAME = "coverage.ec";
+
+    private static final String LOG_TAG = "InstrumentationTestRunner";
+
+    private final Bundle mResults = new Bundle();
+    private Bundle mArguments;
+    private AndroidTestRunner mTestRunner;
+    private boolean mDebug;
+    private boolean mJustCount;
+    private boolean mSuiteAssignmentMode;
+    private int mTestCount;
+    private String mPackageOfTests;
+    private boolean mCoverage;
+    private String mCoverageFilePath;
+    private int mDelayMsec;
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        mArguments = arguments;
+
+        // Apk paths used to search for test classes when using TestSuiteBuilders.
+        String[] apkPaths =
+                {getTargetContext().getPackageCodePath(), getContext().getPackageCodePath()};
+        ClassPathPackageInfoSource.setApkPaths(apkPaths);
+
+        Predicate<TestMethod> testSizePredicate = null;
+        Predicate<TestMethod> testAnnotationPredicate = null;
+        Predicate<TestMethod> testNotAnnotationPredicate = null;
+        String testClassesArg = null;
+        boolean logOnly = false;
+
+        if (arguments != null) {
+            // Test class name passed as an argument should override any meta-data declaration.
+            testClassesArg = arguments.getString(ARGUMENT_TEST_CLASS);
+            mDebug = getBooleanArgument(arguments, "debug");
+            mJustCount = getBooleanArgument(arguments, "count");
+            mSuiteAssignmentMode = getBooleanArgument(arguments, "suiteAssignment");
+            mPackageOfTests = arguments.getString(ARGUMENT_TEST_PACKAGE);
+            testSizePredicate = getSizePredicateFromArg(
+                    arguments.getString(ARGUMENT_TEST_SIZE_PREDICATE));
+            testAnnotationPredicate = getAnnotationPredicate(
+                    arguments.getString(ARGUMENT_ANNOTATION));
+            testNotAnnotationPredicate = getNotAnnotationPredicate(
+                    arguments.getString(ARGUMENT_NOT_ANNOTATION));
+
+            logOnly = getBooleanArgument(arguments, ARGUMENT_LOG_ONLY);
+            mCoverage = getBooleanArgument(arguments, "coverage");
+            mCoverageFilePath = arguments.getString("coverageFile");
+
+            try {
+                Object delay = arguments.get(ARGUMENT_DELAY_MSEC);  // Accept either string or int
+                if (delay != null) mDelayMsec = Integer.parseInt(delay.toString());
+            } catch (NumberFormatException e) {
+                Log.e(LOG_TAG, "Invalid delay_msec parameter", e);
+            }
+        }
+
+        TestSuiteBuilder testSuiteBuilder = new TestSuiteBuilder(getClass().getName(),
+                getTargetContext().getClassLoader());
+
+        if (testSizePredicate != null) {
+            testSuiteBuilder.addRequirements(testSizePredicate);
+        }
+        if (testAnnotationPredicate != null) {
+            testSuiteBuilder.addRequirements(testAnnotationPredicate);
+        }
+        if (testNotAnnotationPredicate != null) {
+            testSuiteBuilder.addRequirements(testNotAnnotationPredicate);
+        }
+
+        if (testClassesArg == null) {
+            if (mPackageOfTests != null) {
+                testSuiteBuilder.includePackages(mPackageOfTests);
+            } else {
+                TestSuite testSuite = getTestSuite();
+                if (testSuite != null) {
+                    testSuiteBuilder.addTestSuite(testSuite);
+                } else {
+                    // no package or class bundle arguments were supplied, and no test suite
+                    // provided so add all tests in application
+                    testSuiteBuilder.includePackages("");
+                }
+            }
+        } else {
+            parseTestClasses(testClassesArg, testSuiteBuilder);
+        }
+
+        testSuiteBuilder.addRequirements(getBuilderRequirements());
+
+        mTestRunner = getAndroidTestRunner();
+        mTestRunner.setContext(getTargetContext());
+        mTestRunner.setInstrumentation(this);
+        mTestRunner.setSkipExecution(logOnly);
+        mTestRunner.setTest(testSuiteBuilder.build());
+        mTestCount = mTestRunner.getTestCases().size();
+        if (mSuiteAssignmentMode) {
+            mTestRunner.addTestListener(new SuiteAssignmentPrinter());
+        } else {
+            WatcherResultPrinter resultPrinter = new WatcherResultPrinter(mTestCount);
+            mTestRunner.addTestListener(new TestPrinter("TestRunner", false));
+            mTestRunner.addTestListener(resultPrinter);
+        }
+        start();
+    }
+
+    /**
+     * Get the arguments passed to this instrumentation.
+     *
+     * @return the Bundle object
+     */
+    public Bundle getArguments() {
+        return mArguments;
+    }
+
+    /**
+     * Add a {@link TestListener}
+     * @hide
+     */
+    protected void addTestListener(TestListener listener){
+        if(mTestRunner!=null && listener!=null){
+            mTestRunner.addTestListener(listener);
+        }
+    }
+
+    List<Predicate<TestMethod>> getBuilderRequirements() {
+        return new ArrayList<Predicate<TestMethod>>();
+    }
+
+    /**
+     * Parses and loads the specified set of test classes
+     *
+     * @param testClassArg - comma-separated list of test classes and methods
+     * @param testSuiteBuilder - builder to add tests to
+     */
+    private void parseTestClasses(String testClassArg, TestSuiteBuilder testSuiteBuilder) {
+        String[] testClasses = testClassArg.split(",");
+        for (String testClass : testClasses) {
+            parseTestClass(testClass, testSuiteBuilder);
+        }
+    }
+
+    /**
+     * Parse and load the given test class and, optionally, method
+     *
+     * @param testClassName - full package name of test class and optionally method to add.
+     *        Expected format: com.android.TestClass#testMethod
+     * @param testSuiteBuilder - builder to add tests to
+     */
+    private void parseTestClass(String testClassName, TestSuiteBuilder testSuiteBuilder) {
+        int methodSeparatorIndex = testClassName.indexOf('#');
+        String testMethodName = null;
+
+        if (methodSeparatorIndex > 0) {
+            testMethodName = testClassName.substring(methodSeparatorIndex + 1);
+            testClassName = testClassName.substring(0, methodSeparatorIndex);
+        }
+        testSuiteBuilder.addTestClassByName(testClassName, testMethodName, getTargetContext());
+    }
+
+    protected AndroidTestRunner getAndroidTestRunner() {
+        return new AndroidTestRunner();
+    }
+
+    private boolean getBooleanArgument(Bundle arguments, String tag) {
+        String tagString = arguments.getString(tag);
+        return tagString != null && Boolean.parseBoolean(tagString);
+    }
+
+    /*
+     * Returns the size predicate object, corresponding to the "size" argument value.
+     */
+    private Predicate<TestMethod> getSizePredicateFromArg(String sizeArg) {
+
+        if (SMALL_SUITE.equals(sizeArg)) {
+            return SELECT_SMALL;
+        } else if (MEDIUM_SUITE.equals(sizeArg)) {
+            return SELECT_MEDIUM;
+        } else if (LARGE_SUITE.equals(sizeArg)) {
+            return SELECT_LARGE;
+        } else {
+            return null;
+        }
+    }
+
+   /**
+    * Returns the test predicate object, corresponding to the annotation class value provided via
+    * the {@link #ARGUMENT_ANNOTATION} argument.
+    *
+    * @return the predicate or <code>null</code>
+    */
+    private Predicate<TestMethod> getAnnotationPredicate(String annotationClassName) {
+        Class<? extends Annotation> annotationClass = getAnnotationClass(annotationClassName);
+        if (annotationClass != null) {
+            return hasAnnotation(annotationClass);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the negative test predicate object, corresponding to the annotation class value
+     * provided via the {@link #ARGUMENT_NOT_ANNOTATION} argument.
+     *
+     * @return the predicate or <code>null</code>
+     */
+     private Predicate<TestMethod> getNotAnnotationPredicate(String annotationClassName) {
+         Class<? extends Annotation> annotationClass = getAnnotationClass(annotationClassName);
+         if (annotationClass != null) {
+             return TestPredicates.not(hasAnnotation(annotationClass));
+         }
+         return null;
+     }
+
+    /**
+     * Helper method to return the annotation class with specified name
+     *
+     * @param annotationClassName the fully qualified name of the class
+     * @return the annotation class or <code>null</code>
+     */
+    private Class<? extends Annotation> getAnnotationClass(String annotationClassName) {
+        if (annotationClassName == null) {
+            return null;
+        }
+        try {
+           Class<?> annotationClass = Class.forName(annotationClassName);
+           if (annotationClass.isAnnotation()) {
+               return (Class<? extends Annotation>)annotationClass;
+           } else {
+               Log.e(LOG_TAG, String.format("Provided annotation value %s is not an Annotation",
+                       annotationClassName));
+           }
+        } catch (ClassNotFoundException e) {
+            Log.e(LOG_TAG, String.format("Could not find class for specified annotation %s",
+                    annotationClassName));
+        }
+        return null;
+    }
+
+    /**
+     * Initialize the current thread as a looper.
+     * <p/>
+     * Exposed for unit testing.
+     */
+    void prepareLooper() {
+        Looper.prepare();
+    }
+
+    @Override
+    public void onStart() {
+        prepareLooper();
+
+        if (mJustCount) {
+            mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
+            mResults.putInt(REPORT_KEY_NUM_TOTAL, mTestCount);
+            finish(Activity.RESULT_OK, mResults);
+        } else {
+            if (mDebug) {
+                Debug.waitForDebugger();
+            }
+
+            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+            PrintStream writer = new PrintStream(byteArrayOutputStream);
+            try {
+                StringResultPrinter resultPrinter = new StringResultPrinter(writer);
+
+                mTestRunner.addTestListener(resultPrinter);
+
+                long startTime = System.currentTimeMillis();
+                mTestRunner.runTest();
+                long runTime = System.currentTimeMillis() - startTime;
+
+                resultPrinter.printResult(mTestRunner.getTestResult(), runTime);
+            } catch (Throwable t) {
+                // catch all exceptions so a more verbose error message can be outputted
+                writer.println(String.format("Test run aborted due to unexpected exception: %s",
+                                t.getMessage()));
+                t.printStackTrace(writer);
+            } finally {
+                mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                        String.format("\nTest results for %s=%s",
+                        mTestRunner.getTestClassName(),
+                        byteArrayOutputStream.toString()));
+
+                if (mCoverage) {
+                    generateCoverageReport();
+                }
+                writer.close();
+
+                finish(Activity.RESULT_OK, mResults);
+            }
+        }
+    }
+
+    public TestSuite getTestSuite() {
+        return getAllTests();
+    }
+
+    /**
+     * Override this to define all of the tests to run in your package.
+     */
+    public TestSuite getAllTests() {
+        return null;
+    }
+
+    /**
+     * Override this to provide access to the class loader of your package.
+     */
+    public ClassLoader getLoader() {
+        return null;
+    }
+
+    private void generateCoverageReport() {
+        // use reflection to call emma dump coverage method, to avoid
+        // always statically compiling against emma jar
+        String coverageFilePath = getCoverageFilePath();
+        java.io.File coverageFile = new java.io.File(coverageFilePath);
+        try {
+            Class<?> emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
+            Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData",
+                    coverageFile.getClass(), boolean.class, boolean.class);
+
+            dumpCoverageMethod.invoke(null, coverageFile, false, false);
+            // output path to generated coverage file so it can be parsed by a test harness if
+            // needed
+            mResults.putString(REPORT_KEY_COVERAGE_PATH, coverageFilePath);
+            // also output a more user friendly msg
+            final String currentStream = mResults.getString(
+                    Instrumentation.REPORT_KEY_STREAMRESULT);
+            mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                String.format("%s\nGenerated code coverage data to %s", currentStream,
+                coverageFilePath));
+        } catch (ClassNotFoundException e) {
+            reportEmmaError("Is emma jar on classpath?", e);
+        } catch (SecurityException e) {
+            reportEmmaError(e);
+        } catch (NoSuchMethodException e) {
+            reportEmmaError(e);
+        } catch (IllegalArgumentException e) {
+            reportEmmaError(e);
+        } catch (IllegalAccessException e) {
+            reportEmmaError(e);
+        } catch (InvocationTargetException e) {
+            reportEmmaError(e);
+        }
+    }
+
+    private String getCoverageFilePath() {
+        if (mCoverageFilePath == null) {
+            return getTargetContext().getFilesDir().getAbsolutePath() + File.separator +
+                   DEFAULT_COVERAGE_FILE_NAME;
+        } else {
+            return mCoverageFilePath;
+        }
+    }
+
+    private void reportEmmaError(Exception e) {
+        reportEmmaError("", e);
+    }
+
+    private void reportEmmaError(String hint, Exception e) {
+        String msg = "Failed to generate emma coverage. " + hint;
+        Log.e(LOG_TAG, msg, e);
+        mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "\nError: " + msg);
+    }
+
+    // TODO kill this, use status() and prettyprint model for better output
+    private class StringResultPrinter extends ResultPrinter {
+
+        public StringResultPrinter(PrintStream writer) {
+            super(writer);
+        }
+
+        public synchronized void printResult(TestResult result, long runTime) {
+            printHeader(runTime);
+            printFooter(result);
+        }
+    }
+
+    /**
+     * This class sends status reports back to the IInstrumentationWatcher about
+     * which suite each test belongs.
+     */
+    private class SuiteAssignmentPrinter implements TestListener {
+
+        private Bundle mTestResult;
+        private long mStartTime;
+        private long mEndTime;
+        private boolean mTimingValid;
+
+        public SuiteAssignmentPrinter() {
+        }
+
+        /**
+         * send a status for the start of a each test, so long tests can be seen as "running"
+         */
+        public void startTest(Test test) {
+            mTimingValid = true;
+            mStartTime = System.currentTimeMillis();
+        }
+
+        /**
+         * @see junit.framework.TestListener#addError(Test, Throwable)
+         */
+        public void addError(Test test, Throwable t) {
+            mTimingValid = false;
+        }
+
+        /**
+         * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+         */
+        public void addFailure(Test test, AssertionFailedError t) {
+            mTimingValid = false;
+        }
+
+        /**
+         * @see junit.framework.TestListener#endTest(Test)
+         */
+        public void endTest(Test test) {
+            float runTime;
+            String assignmentSuite;
+            mEndTime = System.currentTimeMillis();
+            mTestResult = new Bundle();
+
+            if (!mTimingValid || mStartTime < 0) {
+                assignmentSuite = "NA";
+                runTime = -1;
+            } else {
+                runTime = mEndTime - mStartTime;
+                if (runTime < SMALL_SUITE_MAX_RUNTIME
+                        && !InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
+                    assignmentSuite = SMALL_SUITE;
+                } else if (runTime < MEDIUM_SUITE_MAX_RUNTIME) {
+                    assignmentSuite = MEDIUM_SUITE;
+                } else {
+                    assignmentSuite = LARGE_SUITE;
+                }
+            }
+            // Clear mStartTime so that we can verify that it gets set next time.
+            mStartTime = -1;
+
+            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                    test.getClass().getName() + "#" + ((TestCase) test).getName()
+                    + "\nin " + assignmentSuite + " suite\nrunTime: "
+                    + String.valueOf(runTime) + "\n");
+            mTestResult.putFloat(REPORT_KEY_RUN_TIME, runTime);
+            mTestResult.putString(REPORT_KEY_SUITE_ASSIGNMENT, assignmentSuite);
+
+            sendStatus(0, mTestResult);
+        }
+    }
+
+    /**
+     * This class sends status reports back to the IInstrumentationWatcher
+     */
+    private class WatcherResultPrinter implements TestListener {
+        private final Bundle mResultTemplate;
+        Bundle mTestResult;
+        int mTestNum = 0;
+        int mTestResultCode = 0;
+        String mTestClass = null;
+
+        public WatcherResultPrinter(int numTests) {
+            mResultTemplate = new Bundle();
+            mResultTemplate.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
+            mResultTemplate.putInt(REPORT_KEY_NUM_TOTAL, numTests);
+        }
+
+        /**
+         * send a status for the start of a each test, so long tests can be seen
+         * as "running"
+         */
+        public void startTest(Test test) {
+            String testClass = test.getClass().getName();
+            String testName = ((TestCase)test).getName();
+            mTestResult = new Bundle(mResultTemplate);
+            mTestResult.putString(REPORT_KEY_NAME_CLASS, testClass);
+            mTestResult.putString(REPORT_KEY_NAME_TEST, testName);
+            mTestResult.putInt(REPORT_KEY_NUM_CURRENT, ++mTestNum);
+            // pretty printing
+            if (testClass != null && !testClass.equals(mTestClass)) {
+                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                        String.format("\n%s:", testClass));
+                mTestClass = testClass;
+            } else {
+                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "");
+            }
+
+            Method testMethod = null;
+            try {
+                testMethod = test.getClass().getMethod(testName);
+                // Report total number of iterations, if test is repetitive
+                if (testMethod.isAnnotationPresent(RepetitiveTest.class)) {
+                    int numIterations = testMethod.getAnnotation(
+                        RepetitiveTest.class).numIterations();
+                    mTestResult.putInt(REPORT_KEY_NUM_ITERATIONS, numIterations);
+                }
+            } catch (NoSuchMethodException e) {
+                // ignore- the test with given name does not exist. Will be handled during test
+                // execution
+            }
+
+            // The delay_msec parameter is normally used to provide buffers of idle time
+            // for power measurement purposes. To make sure there is a delay before and after
+            // every test in a suite, we delay *after* every test (see endTest below) and also
+            // delay *before* the first test. So, delay test1 delay test2 delay.
+
+            try {
+                if (mTestNum == 1) Thread.sleep(mDelayMsec);
+            } catch (InterruptedException e) {
+                throw new IllegalStateException(e);
+            }
+
+            sendStatus(REPORT_VALUE_RESULT_START, mTestResult);
+            mTestResultCode = 0;
+        }
+
+        /**
+         * @see junit.framework.TestListener#addError(Test, Throwable)
+         */
+        public void addError(Test test, Throwable t) {
+            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
+            mTestResultCode = REPORT_VALUE_RESULT_ERROR;
+            // pretty printing
+            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                String.format("\nError in %s:\n%s",
+                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
+        }
+
+        /**
+         * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+         */
+        public void addFailure(Test test, AssertionFailedError t) {
+            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
+            mTestResultCode = REPORT_VALUE_RESULT_FAILURE;
+            // pretty printing
+            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                String.format("\nFailure in %s:\n%s",
+                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
+        }
+
+        /**
+         * @see junit.framework.TestListener#endTest(Test)
+         */
+        public void endTest(Test test) {
+            if (mTestResultCode == 0) {
+                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ".");
+            }
+            sendStatus(mTestResultCode, mTestResult);
+
+            try { // Sleep after every test, if specified
+                Thread.sleep(mDelayMsec);
+            } catch (InterruptedException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        // TODO report the end of the cycle
+    }
+}
diff --git a/android/test/InstrumentationTestSuite.java b/android/test/InstrumentationTestSuite.java
new file mode 100644
index 0000000..a53fa26
--- /dev/null
+++ b/android/test/InstrumentationTestSuite.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.app.Instrumentation;
+
+import junit.framework.TestSuite;
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+/**
+ * A {@link junit.framework.TestSuite} that injects {@link android.app.Instrumentation} into
+ * {@link InstrumentationTestCase} before running them.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class InstrumentationTestSuite extends TestSuite {
+
+    private final Instrumentation mInstrumentation;
+
+    /**
+     * @param instr The instrumentation that will be injected into each
+     *   test before running it.
+     */
+    public InstrumentationTestSuite(Instrumentation instr) {
+        mInstrumentation = instr;
+    }
+
+
+    public InstrumentationTestSuite(String name, Instrumentation instr) {
+        super(name);
+        mInstrumentation = instr;
+    }
+
+    /**
+     * @param theClass Inspected for methods starting with 'test'
+     * @param instr The instrumentation to inject into each test before
+     *   running.
+     */
+    public InstrumentationTestSuite(final Class theClass, Instrumentation instr) {
+        super(theClass);
+        mInstrumentation = instr;
+    }
+
+
+    @Override
+    public void addTestSuite(Class testClass) {
+        addTest(new InstrumentationTestSuite(testClass, mInstrumentation));
+    }
+
+
+    @Override
+    public void runTest(Test test, TestResult result) {
+
+        if (test instanceof InstrumentationTestCase) {
+            ((InstrumentationTestCase) test).injectInstrumentation(mInstrumentation);
+        }
+
+        // run the test as usual
+        super.runTest(test, result);
+    }
+}
diff --git a/android/test/IsolatedContext.java b/android/test/IsolatedContext.java
new file mode 100644
index 0000000..dd4a9a3
--- /dev/null
+++ b/android/test/IsolatedContext.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.accounts.AccountManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.test.mock.MockAccountManager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+
+/**
+ * A mock context which prevents its users from talking to the rest of the device while
+ * stubbing enough methods to satify code that tries to talk to other packages.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class IsolatedContext extends ContextWrapper {
+
+    private ContentResolver mResolver;
+    private final AccountManager mMockAccountManager;
+
+    private List<Intent> mBroadcastIntents = new ArrayList<>();
+
+    public IsolatedContext(
+            ContentResolver resolver, Context targetContext) {
+        super(targetContext);
+        mResolver = resolver;
+        mMockAccountManager = MockAccountManager.newMockAccountManager(IsolatedContext.this);
+    }
+
+    /** Returns the list of intents that were broadcast since the last call to this method. */
+    public List<Intent> getAndClearBroadcastIntents() {
+        List<Intent> intents = mBroadcastIntents;
+        mBroadcastIntents = new ArrayList<>();
+        return intents;
+    }
+
+    @Override
+    public ContentResolver getContentResolver() {
+        // We need to return the real resolver so that MailEngine.makeRight can get to the
+        // subscribed feeds provider. TODO: mock out subscribed feeds too.
+        return mResolver;
+    }
+
+    @Override
+    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+        return false;
+    }
+
+    @Override
+    public boolean bindService(Intent service, int flags, Executor executor,
+            ServiceConnection conn) {
+        return false;
+    }
+
+    @Override
+    public boolean bindIsolatedService(Intent service, int flags, String instanceName,
+            Executor executor, ServiceConnection conn) {
+        return false;
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+        return null;
+    }
+
+    @Override
+    public void unregisterReceiver(BroadcastReceiver receiver) {
+        // Ignore
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent) {
+        mBroadcastIntents.add(intent);
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
+        mBroadcastIntents.add(intent);
+    }
+
+    @Override
+    public int checkUriPermission(
+            Uri uri, String readPermission, String writePermission, int pid,
+            int uid, int modeFlags) {
+        return PackageManager.PERMISSION_GRANTED;
+    }
+
+    @Override
+    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+        return PackageManager.PERMISSION_GRANTED;
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        if (Context.ACCOUNT_SERVICE.equals(name)) {
+            return mMockAccountManager;
+        }
+        // No other services exist in this context.
+        return null;
+    }
+
+    @Override
+    public File getFilesDir() {
+        return new File("/dev/null");
+    }
+}
diff --git a/android/test/LaunchPerformanceBase.java b/android/test/LaunchPerformanceBase.java
new file mode 100644
index 0000000..62c90d6
--- /dev/null
+++ b/android/test/LaunchPerformanceBase.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Bundle;
+
+
+/**
+ * Base class for all launch performance Instrumentation classes.
+ *
+ * @hide
+ */
+@Deprecated
+public class LaunchPerformanceBase extends Instrumentation {
+
+    public static final String LOG_TAG = "Launch Performance";
+
+    protected Bundle mResults;
+    protected Intent mIntent;
+
+    public LaunchPerformanceBase() {
+        mResults = new Bundle();
+        mIntent = new Intent(Intent.ACTION_MAIN);
+        mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        setAutomaticPerformanceSnapshots();
+    }
+
+    /**
+     * Launches intent, and waits for idle before returning.
+     *
+     * @hide
+     */
+    protected void LaunchApp() {
+        startActivitySync(mIntent);
+        waitForIdleSync();
+    }
+}
diff --git a/android/test/LoaderTestCase.java b/android/test/LoaderTestCase.java
new file mode 100644
index 0000000..c8564c2
--- /dev/null
+++ b/android/test/LoaderTestCase.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.test;
+
+import android.content.Loader;
+import android.content.Loader.OnLoadCompleteListener;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import java.util.concurrent.ArrayBlockingQueue;
+
+/**
+ * A convenience class for testing {@link Loader}s. This test case
+ * provides a simple way to synchronously get the result from a Loader making
+ * it easy to assert that the Loader returns the expected result.
+ */
+public class LoaderTestCase extends AndroidTestCase {
+    static {
+        // Force class loading of AsyncTask on the main thread so that it's handlers are tied to
+        // the main thread and responses from the worker thread get delivered on the main thread.
+        // The tests are run on another thread, allowing them to block waiting on a response from
+        // the code running on the main thread. The main thread can't block since the AysncTask
+        // results come in via the event loop.
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... args) {return null;}
+            @Override
+            protected void onPostExecute(Void result) {}
+        };
+    }
+
+    /**
+     * Runs a Loader synchronously and returns the result of the load. The loader will
+     * be started, stopped, and destroyed by this method so it cannot be reused.
+     *
+     * @param loader The loader to run synchronously
+     * @return The result from the loader
+     */
+    public <T> T getLoaderResultSynchronously(final Loader<T> loader) {
+        // The test thread blocks on this queue until the loader puts it's result in
+        final ArrayBlockingQueue<T> queue = new ArrayBlockingQueue<T>(1);
+
+        // This callback runs on the "main" thread and unblocks the test thread
+        // when it puts the result into the blocking queue
+        final OnLoadCompleteListener<T> listener = new OnLoadCompleteListener<T>() {
+            @Override
+            public void onLoadComplete(Loader<T> completedLoader, T data) {
+                // Shut the loader down
+                completedLoader.unregisterListener(this);
+                completedLoader.stopLoading();
+                completedLoader.reset();
+
+                // Store the result, unblocking the test thread
+                queue.add(data);
+            }
+        };
+
+        // This handler runs on the "main" thread of the process since AsyncTask
+        // is documented as needing to run on the main thread and many Loaders use
+        // AsyncTask
+        final Handler mainThreadHandler = new Handler(Looper.getMainLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                loader.registerListener(0, listener);
+                loader.startLoading();
+            }
+        };
+
+        // Ask the main thread to start the loading process
+        mainThreadHandler.sendEmptyMessage(0);
+
+        // Block on the queue waiting for the result of the load to be inserted
+        T result;
+        while (true) {
+            try {
+                result = queue.take();
+                break;
+            } catch (InterruptedException e) {
+                throw new RuntimeException("waiting thread interrupted", e);
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/android/test/MoreAsserts.java b/android/test/MoreAsserts.java
new file mode 100644
index 0000000..d33911a
--- /dev/null
+++ b/android/test/MoreAsserts.java
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import junit.framework.Assert;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.ArrayList;
+import java.util.regex.MatchResult;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Contains additional assertion methods not found in JUnit.
+ * @deprecated Use
+ * <a href="https://github.com/hamcrest">Hamcrest matchers</a> instead.
+ */
+@Deprecated
+public final class MoreAsserts {
+
+    private MoreAsserts() { }
+
+    /**
+     * Asserts that the class  {@code expected} is assignable from the object
+     * {@code actual}. This verifies {@code expected} is a parent class or a
+     * interface that {@code actual} implements.
+     */
+    public static void assertAssignableFrom(Class<?> expected, Object actual) {
+        assertAssignableFrom(expected, actual.getClass());
+    }
+
+    /**
+     * Asserts that class {@code expected} is assignable from the class
+     * {@code actual}. This verifies {@code expected} is a parent class or a
+     * interface that {@code actual} implements.
+     */
+    public static void assertAssignableFrom(Class<?> expected, Class<?> actual) {
+        Assert.assertTrue(
+                "Expected " + expected.getCanonicalName() +
+                        " to be assignable from actual class " + actual.getCanonicalName(),
+                expected.isAssignableFrom(actual));
+    }
+
+    /**
+     * Asserts that {@code actual} is not equal {@code unexpected}, according
+     * to both {@code ==} and {@link Object#equals}.
+     */
+    public static void assertNotEqual(
+            String message, Object unexpected, Object actual) {
+        if (equal(unexpected, actual)) {
+            failEqual(message, unexpected);
+        }
+    }
+
+    /**
+     * Variant of {@link #assertNotEqual(String,Object,Object)} using a
+     * generic message.
+     */
+    public static void assertNotEqual(Object unexpected, Object actual) {
+        assertNotEqual(null, unexpected, actual);
+    }
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates specific
+     * element mismatch.
+     */
+    public static void assertEquals(
+            String message, byte[] expected, byte[] actual) {
+        if (expected.length != actual.length) {
+            failWrongLength(message, expected.length, actual.length);
+        }
+        for (int i = 0; i < expected.length; i++) {
+            if (expected[i] != actual[i]) {
+                failWrongElement(message, i, expected[i], actual[i]);
+            }
+        }
+    }
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates specific
+     * element mismatch.
+     */
+    public static void assertEquals(byte[] expected, byte[] actual) {
+        assertEquals(null, expected, actual);
+    }
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates first
+     * specific element mismatch.
+     */
+    public static void assertEquals(
+            String message, int[] expected, int[] actual) {
+        if (expected.length != actual.length) {
+            failWrongLength(message, expected.length, actual.length);
+        }
+        for (int i = 0; i < expected.length; i++) {
+            if (expected[i] != actual[i]) {
+                failWrongElement(message, i, expected[i], actual[i]);
+            }
+        }
+    }
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates first
+     * specific element mismatch.
+     */
+    public static void assertEquals(int[] expected, int[] actual) {
+        assertEquals(null, expected, actual);
+    }
+
+    /**
+     * @hide Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates first
+     * specific element mismatch.
+     */
+    public static void assertEquals(
+            String message, long[] expected, long[] actual) {
+        if (expected.length != actual.length) {
+            failWrongLength(message, expected.length, actual.length);
+        }
+        for (int i = 0; i < expected.length; i++) {
+            if (expected[i] != actual[i]) {
+                failWrongElement(message, i, expected[i], actual[i]);
+            }
+        }
+    }
+
+    /**
+     * @hide Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates first
+     * specific element mismatch.
+     */
+    public static void assertEquals(long[] expected, long[] actual) {
+        assertEquals(null, expected, actual);
+    }
+
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates first
+     * specific element mismatch.
+     */
+    public static void assertEquals(
+            String message, double[] expected, double[] actual) {
+        if (expected.length != actual.length) {
+            failWrongLength(message, expected.length, actual.length);
+        }
+        for (int i = 0; i < expected.length; i++) {
+            if (expected[i] != actual[i]) {
+                failWrongElement(message, i, expected[i], actual[i]);
+            }
+        }
+    }
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element equals
+     * those in array {@code expected}. On failure, message indicates first
+     * specific element mismatch.
+     */
+    public static void assertEquals(double[] expected, double[] actual) {
+        assertEquals(null, expected, actual);
+    }
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element
+     * is the same as those in array {@code expected}. Note that this uses
+     * {@code equals()} instead of {@code ==} to compare the objects.
+     * {@code null} will be considered equal to {@code null} (unlike SQL).
+     * On failure, message indicates first specific element mismatch.
+     */
+    public static void assertEquals(
+            String message, Object[] expected, Object[] actual) {
+        if (expected.length != actual.length) {
+            failWrongLength(message, expected.length, actual.length);
+        }
+        for (int i = 0; i < expected.length; i++) {
+            Object exp = expected[i];
+            Object act = actual[i];
+            // The following borrowed from java.util.equals(Object[], Object[]).
+            if (!((exp==null) ? act==null : exp.equals(act))) {
+                failWrongElement(message, i, exp, act);
+            }
+        }
+    }
+
+    /**
+     * Asserts that array {@code actual} is the same size and every element
+     * is the same as those in array {@code expected}. Note that this uses
+     * {@code ==} instead of {@code equals()} to compare the objects.
+     * On failure, message indicates first specific element mismatch.
+     */
+    public static void assertEquals(Object[] expected, Object[] actual) {
+        assertEquals(null, expected, actual);
+    }
+
+    /** Asserts that two sets contain the same elements. */
+    public static void assertEquals(
+            String message, Set<? extends Object> expected, Set<? extends Object> actual) {
+        Set<Object> onlyInExpected = new HashSet<Object>(expected);
+        onlyInExpected.removeAll(actual);
+        Set<Object> onlyInActual = new HashSet<Object>(actual);
+        onlyInActual.removeAll(expected);
+        if (onlyInExpected.size() != 0 || onlyInActual.size() != 0) {
+            Set<Object> intersection = new HashSet<Object>(expected);
+            intersection.retainAll(actual);
+            failWithMessage(
+                    message,
+                    "Sets do not match.\nOnly in expected: " + onlyInExpected
+                    + "\nOnly in actual: " + onlyInActual
+                    + "\nIntersection: " + intersection);
+        }
+    }
+
+    /** Asserts that two sets contain the same elements. */
+    public static void assertEquals(Set<? extends Object> expected, Set<? extends Object> actual) {
+        assertEquals(null, expected, actual);
+    }
+
+    /**
+     * Asserts that {@code expectedRegex} exactly matches {@code actual} and
+     * fails with {@code message} if it does not.  The MatchResult is returned
+     * in case the test needs access to any captured groups.  Note that you can
+     * also use this for a literal string, by wrapping your expected string in
+     * {@link Pattern#quote}.
+     */
+    public static MatchResult assertMatchesRegex(
+            String message, String expectedRegex, String actual) {
+        if (actual == null) {
+            failNotMatches(message, expectedRegex, actual);
+        }
+        Matcher matcher = getMatcher(expectedRegex, actual);
+        if (!matcher.matches()) {
+            failNotMatches(message, expectedRegex, actual);
+        }
+        return matcher;
+    }
+
+    /**
+     * Variant of {@link #assertMatchesRegex(String,String,String)} using a
+     * generic message.
+     */
+    public static MatchResult assertMatchesRegex(
+            String expectedRegex, String actual) {
+        return assertMatchesRegex(null, expectedRegex, actual);
+    }
+
+    /**
+     * Asserts that {@code expectedRegex} matches any substring of {@code actual}
+     * and fails with {@code message} if it does not.  The Matcher is returned in
+     * case the test needs access to any captured groups.  Note that you can also
+     * use this for a literal string, by wrapping your expected string in
+     * {@link Pattern#quote}.
+     */
+    public static MatchResult assertContainsRegex(
+            String message, String expectedRegex, String actual) {
+        if (actual == null) {
+            failNotContains(message, expectedRegex, actual);
+        }
+        Matcher matcher = getMatcher(expectedRegex, actual);
+        if (!matcher.find()) {
+            failNotContains(message, expectedRegex, actual);
+        }
+        return matcher;
+    }
+
+    /**
+     * Variant of {@link #assertContainsRegex(String,String,String)} using a
+     * generic message.
+     */
+    public static MatchResult assertContainsRegex(
+            String expectedRegex, String actual) {
+        return assertContainsRegex(null, expectedRegex, actual);
+    }
+
+    /**
+     * Asserts that {@code expectedRegex} does not exactly match {@code actual},
+     * and fails with {@code message} if it does. Note that you can also use
+     * this for a literal string, by wrapping your expected string in
+     * {@link Pattern#quote}.
+     */
+    public static void assertNotMatchesRegex(
+            String message, String expectedRegex, String actual) {
+        Matcher matcher = getMatcher(expectedRegex, actual);
+        if (matcher.matches()) {
+            failMatch(message, expectedRegex, actual);
+        }
+    }
+
+    /**
+     * Variant of {@link #assertNotMatchesRegex(String,String,String)} using a
+     * generic message.
+     */
+    public static void assertNotMatchesRegex(
+            String expectedRegex, String actual) {
+        assertNotMatchesRegex(null, expectedRegex, actual);
+    }
+
+    /**
+     * Asserts that {@code expectedRegex} does not match any substring of
+     * {@code actual}, and fails with {@code message} if it does.  Note that you
+     * can also use this for a literal string, by wrapping your expected string
+     * in {@link Pattern#quote}.
+     */
+    public static void assertNotContainsRegex(
+            String message, String expectedRegex, String actual) {
+        Matcher matcher = getMatcher(expectedRegex, actual);
+        if (matcher.find()) {
+            failContains(message, expectedRegex, actual);
+        }
+    }
+
+    /**
+     * Variant of {@link #assertNotContainsRegex(String,String,String)} using a
+     * generic message.
+     */
+    public static void assertNotContainsRegex(
+            String expectedRegex, String actual) {
+        assertNotContainsRegex(null, expectedRegex, actual);
+    }
+
+    /**
+     * Asserts that {@code actual} contains precisely the elements
+     * {@code expected}, and in the same order.
+     */
+    public static void assertContentsInOrder(
+            String message, Iterable<?> actual, Object... expected) {
+        ArrayList actualList = new ArrayList();
+        for (Object o : actual) {
+            actualList.add(o);
+        }
+        Assert.assertEquals(message, Arrays.asList(expected), actualList);
+    }
+
+    /**
+     * Variant of assertContentsInOrder(String, Iterable<?>, Object...)
+     * using a generic message.
+     */
+    public static void assertContentsInOrder(
+            Iterable<?> actual, Object... expected) {
+        assertContentsInOrder((String) null, actual, expected);
+    }
+
+    /**
+     * Asserts that {@code actual} contains precisely the elements
+     * {@code expected}, but in any order.
+     */
+    public static void assertContentsInAnyOrder(String message, Iterable<?> actual,
+            Object... expected) {
+        HashMap<Object, Object> expectedMap = new HashMap<Object, Object>(expected.length);
+        for (Object expectedObj : expected) {
+            expectedMap.put(expectedObj, expectedObj);
+        }
+
+        for (Object actualObj : actual) {
+            if (expectedMap.remove(actualObj) == null) {
+                failWithMessage(message, "Extra object in actual: (" + actualObj.toString() + ")");
+            }
+        }
+
+        if (expectedMap.size() > 0) {
+            failWithMessage(message, "Extra objects in expected.");
+        }
+    }
+
+    /**
+     * Variant of assertContentsInAnyOrder(String, Iterable<?>, Object...)
+     * using a generic message.
+     */
+    public static void assertContentsInAnyOrder(Iterable<?> actual, Object... expected) {
+        assertContentsInAnyOrder((String)null, actual, expected);
+    }
+
+    /**
+     * Asserts that {@code iterable} is empty.
+     */
+    public static void assertEmpty(String message, Iterable<?> iterable) {
+        if (iterable.iterator().hasNext()) {
+            failNotEmpty(message, iterable.toString());
+        }
+    }
+
+    /**
+     * Variant of {@link #assertEmpty(String, Iterable)} using a
+     * generic message.
+     */
+    public static void assertEmpty(Iterable<?> iterable) {
+        assertEmpty(null, iterable);
+    }
+
+    /**
+     * Asserts that {@code map} is empty.
+     */
+    public static void assertEmpty(String message, Map<?,?> map) {
+        if (!map.isEmpty()) {
+            failNotEmpty(message, map.toString());
+        }
+    }
+
+    /**
+     * Variant of {@link #assertEmpty(String, Map)} using a generic
+     * message.
+     */
+    public  static void assertEmpty(Map<?,?> map) {
+        assertEmpty(null, map);
+    }
+
+    /**
+     * Asserts that {@code iterable} is not empty.
+     */
+    public static void assertNotEmpty(String message, Iterable<?> iterable) {
+        if (!iterable.iterator().hasNext()) {
+            failEmpty(message);
+        }
+    }
+
+    /**
+     * Variant of assertNotEmpty(String, Iterable<?>)
+     * using a generic message.
+     */
+    public static void assertNotEmpty(Iterable<?> iterable) {
+        assertNotEmpty(null, iterable);
+    }
+
+    /**
+     * Asserts that {@code map} is not empty.
+     */
+    public static void assertNotEmpty(String message, Map<?,?> map) {
+        if (map.isEmpty()) {
+            failEmpty(message);
+        }
+    }
+
+    /**
+     * Variant of {@link #assertNotEmpty(String, Map)} using a generic
+     * message.
+     */
+    public static void assertNotEmpty(Map<?,?> map) {
+        assertNotEmpty(null, map);
+    }
+
+    /**
+     * Utility for testing equals() and hashCode() results at once.
+     * Tests that lhs.equals(rhs) matches expectedResult, as well as
+     * rhs.equals(lhs).  Also tests that hashCode() return values are
+     * equal if expectedResult is true.  (hashCode() is not tested if
+     * expectedResult is false, as unequal objects can have equal hashCodes.)
+     *
+     * @param lhs An Object for which equals() and hashCode() are to be tested.
+     * @param rhs As lhs.
+     * @param expectedResult True if the objects should compare equal,
+     *   false if not.
+     */
+    public static void checkEqualsAndHashCodeMethods(
+            String message, Object lhs, Object rhs, boolean expectedResult) {
+
+        if ((lhs == null) && (rhs == null)) {
+            Assert.assertTrue(
+                    "Your check is dubious...why would you expect null != null?",
+                    expectedResult);
+            return;
+        }
+
+        if ((lhs == null) || (rhs == null)) {
+            Assert.assertFalse(
+                    "Your check is dubious...why would you expect an object "
+                            + "to be equal to null?", expectedResult);
+        }
+
+        if (lhs != null) {
+            Assert.assertEquals(message, expectedResult, lhs.equals(rhs));
+        }
+        if (rhs != null) {
+            Assert.assertEquals(message, expectedResult, rhs.equals(lhs));
+        }
+
+        if (expectedResult) {
+            String hashMessage =
+                    "hashCode() values for equal objects should be the same";
+            if (message != null) {
+                hashMessage += ": " + message;
+            }
+            Assert.assertTrue(hashMessage, lhs.hashCode() == rhs.hashCode());
+        }
+    }
+
+    /**
+     * Variant of
+     * checkEqualsAndHashCodeMethods(String,Object,Object,boolean...)}
+     * using a generic message.
+     */
+    public static void checkEqualsAndHashCodeMethods(Object lhs, Object rhs,
+            boolean expectedResult) {
+        checkEqualsAndHashCodeMethods((String) null, lhs, rhs, expectedResult);
+    }
+
+    private static Matcher getMatcher(String expectedRegex, String actual) {
+        Pattern pattern = Pattern.compile(expectedRegex);
+        return pattern.matcher(actual);
+    }
+
+    private static void failEqual(String message, Object unexpected) {
+        failWithMessage(message, "expected not to be:<" + unexpected + ">");
+    }
+
+    private static void failWrongLength(
+            String message, int expected, int actual) {
+        failWithMessage(message, "expected array length:<" + expected
+                + "> but was:<" + actual + '>');
+    }
+
+    private static void failWrongElement(
+            String message, int index, Object expected, Object actual) {
+        failWithMessage(message, "expected array element[" + index + "]:<"
+                + expected + "> but was:<" + actual + '>');
+    }
+
+    private static void failNotMatches(
+            String message, String expectedRegex, String actual) {
+        String actualDesc = (actual == null) ? "null" : ('<' + actual + '>');
+        failWithMessage(message, "expected to match regex:<" + expectedRegex
+                + "> but was:" + actualDesc);
+    }
+
+    private static void failNotContains(
+            String message, String expectedRegex, String actual) {
+        String actualDesc = (actual == null) ? "null" : ('<' + actual + '>');
+        failWithMessage(message, "expected to contain regex:<" + expectedRegex
+                + "> but was:" + actualDesc);
+    }
+
+    private static void failMatch(
+            String message, String expectedRegex, String actual) {
+        failWithMessage(message, "expected not to match regex:<" + expectedRegex
+                + "> but was:<" + actual + '>');
+    }
+
+    private static void failContains(
+            String message, String expectedRegex, String actual) {
+        failWithMessage(message, "expected not to contain regex:<" + expectedRegex
+                + "> but was:<" + actual + '>');
+    }
+
+    private static void failNotEmpty(
+            String message, String actual) {
+        failWithMessage(message, "expected to be empty, but contained: <"
+                + actual + ">");
+    }
+
+    private static void failEmpty(String message) {
+        failWithMessage(message, "expected not to be empty, but was");
+    }
+
+    private static void failWithMessage(String userMessage, String ourMessage) {
+        Assert.fail((userMessage == null)
+                ? ourMessage
+                : userMessage + ' ' + ourMessage);
+    }
+
+    private static boolean equal(Object a, Object b) {
+        return a == b || (a != null && a.equals(b));
+    }
+
+}
diff --git a/android/test/NoExecTestResult.java b/android/test/NoExecTestResult.java
new file mode 100644
index 0000000..a01b6aa
--- /dev/null
+++ b/android/test/NoExecTestResult.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.test;
+
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+/**
+ * A benign test result that does no actually test execution, just runs
+ * through the motions
+ *
+ * {@hide} Not needed for SDK.
+ */
+@Deprecated
+class NoExecTestResult extends TestResult {
+
+    /**
+     * Override parent to just inform listeners of test,
+     * and skip test execution.
+     */
+    @Override
+    protected void run(final TestCase test) {
+        startTest(test);
+        endTest(test);
+    }
+
+}
diff --git a/android/test/PerformanceTestCase.java b/android/test/PerformanceTestCase.java
new file mode 100644
index 0000000..2584da2
--- /dev/null
+++ b/android/test/PerformanceTestCase.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2006 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.test;
+
+/**
+ * More complex interface performance for test cases.
+ *
+ * If you want your test to be used as a performance test, you must
+ * implement this interface.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public interface PerformanceTestCase
+{
+    /**
+     * Callbacks for {@link PerformanceTestCase}.
+     */
+    public interface Intermediates
+    {
+        void setInternalIterations(int count);
+        void startTiming(boolean realTime);
+        void addIntermediate(String name);
+        void addIntermediate(String name, long timeInNS);
+        void finishTiming(boolean realTime);
+    }
+
+    /**
+     * Set up to begin performance tests. The 'intermediates' is a
+     * communication channel to send back intermediate performance numbers --
+     * if you use it, you will probably want to ensure your test is only
+     * executed once by returning 1.  Otherwise, return 0 to allow the test
+     * harness to decide the number of iterations.
+     *
+     * <p>If you return a non-zero iteration count, you should call
+     * {@link Intermediates#startTiming intermediates.startTiming} and
+     * {@link Intermediates#finishTiming intermediates.endTiming} to report the
+     * duration of the test whose performance should actually be measured.
+     *
+     * @param intermediates Callback for sending intermediate results.
+     *
+     * @return int Maximum number of iterations to run, or 0 to let the caller
+     * decide.
+     */
+    int startPerformance(Intermediates intermediates);
+
+    /**
+     * This method is used to determine what modes this test case can run in.
+     *
+     * @return true if this test case can only be run in performance mode.
+     */
+    boolean isPerformanceOnly();
+}
+
diff --git a/android/test/ProviderTestCase.java b/android/test/ProviderTestCase.java
new file mode 100644
index 0000000..4108f34
--- /dev/null
+++ b/android/test/ProviderTestCase.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.test.mock.MockContext;
+import android.test.mock.MockContentResolver;
+import android.database.DatabaseUtils;
+
+/**
+ * If you would like to test a single content provider with an
+ * {@link InstrumentationTestCase}, this provides some of the boiler plate in {@link #setUp} and
+ * {@link #tearDown}.
+ *
+ * @deprecated this class extends InstrumentationTestCase but should extend AndroidTestCase. Use
+ * ProviderTestCase2, which corrects this problem, instead.
+ */
+@Deprecated
+public abstract class ProviderTestCase<T extends ContentProvider>
+       extends InstrumentationTestCase {
+
+    Class<T> mProviderClass;
+    String mProviderAuthority;
+
+    private IsolatedContext mProviderContext;
+    private MockContentResolver mResolver;
+
+    public ProviderTestCase(Class<T> providerClass, String providerAuthority) {
+        mProviderClass = providerClass;
+        mProviderAuthority = providerAuthority;
+    }
+
+    /**
+     * The content provider that will be set up for use in each test method.
+     */
+    private T mProvider;
+
+    public T getProvider() {
+        return mProvider;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mResolver = new MockContentResolver();
+        final String filenamePrefix = "test.";
+        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
+                new MockContext(), // The context that most methods are delegated to
+                getInstrumentation().getTargetContext(), // The context that file methods are delegated to
+                filenamePrefix);
+        mProviderContext = new IsolatedContext(mResolver, targetContextWrapper);
+
+        mProvider = ProviderTestCase2.createProviderForTest(
+                mProviderContext, mProviderClass, mProviderAuthority);
+        mResolver.addProvider(mProviderAuthority, getProvider());
+    }
+
+    /**
+     * Tears down the environment for the test fixture.
+     * <p>
+     * Calls {@link android.content.ContentProvider#shutdown()} on the
+     * {@link android.content.ContentProvider} represented by mProvider.
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        mProvider.shutdown();
+        super.tearDown();
+    }
+
+    public MockContentResolver getMockContentResolver() {
+        return mResolver;
+    }
+
+    public IsolatedContext getMockContext() {
+        return mProviderContext;
+    }
+
+    public static <T extends ContentProvider> ContentResolver newResolverWithContentProviderFromSql(
+            Context targetContext, Class<T> providerClass, String authority,
+            String databaseName, int databaseVersion, String sql)
+            throws IllegalAccessException, InstantiationException {
+        final String filenamePrefix = "test.";
+        MockContentResolver resolver = new MockContentResolver();
+        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
+                new MockContext(), // The context that most methods are delegated to
+                targetContext, // The context that file methods are delegated to
+                filenamePrefix);
+        Context context = new IsolatedContext(
+                resolver, targetContextWrapper);
+        DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql);
+
+        T provider = ProviderTestCase2.createProviderForTest(context, providerClass, authority);
+        resolver.addProvider(authority, provider);
+
+        return resolver;
+    }
+}
diff --git a/android/test/ProviderTestCase2.java b/android/test/ProviderTestCase2.java
new file mode 100644
index 0000000..be18b53
--- /dev/null
+++ b/android/test/ProviderTestCase2.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.content.res.Resources;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContext;
+import android.test.mock.MockContentResolver;
+import android.database.DatabaseUtils;
+
+import java.io.File;
+
+/**
+ * This test case class provides a framework for testing a single
+ * {@link ContentProvider} and for testing your app code with an
+ * isolated content provider. Instead of using the system map of
+ * providers that is based on the manifests of other applications, the test
+ * case creates its own internal map. It then uses this map to resolve providers
+ * given an authority. This allows you to inject test providers and to null out
+ * providers that you do not want to use.
+ * <p>
+ *      This test case also sets up the following mock objects:
+ * </p>
+ * <ul>
+ *      <li>
+ *          An {@link android.test.IsolatedContext} that stubs out Context methods that might
+ *          affect the rest of the running system, while allowing tests to do real file and
+ *          database work.
+ *      </li>
+ *      <li>
+ *          A {@link android.test.mock.MockContentResolver} that provides the functionality of a
+ *          regular content resolver, but uses {@link IsolatedContext}. It stubs out
+ *          {@link ContentResolver#notifyChange(Uri, ContentObserver, boolean)} to
+ *          prevent the test from affecting the running system.
+ *      </li>
+ *      <li>
+ *          An instance of the provider under test, running in an {@link IsolatedContext}.
+ *      </li>
+ * </ul>
+ * <p>
+ *      This framework is set up automatically by the base class' {@link #setUp()} method. If you
+ *      override this method, you must call the super method as the first statement in
+ *      your override.
+ * </p>
+ * <p>
+ *     In order for their tests to be run, concrete subclasses must provide their own
+ *     constructor with no arguments. This constructor must call
+ *     {@link #ProviderTestCase2(Class, String)} as  its first operation.
+ * </p>
+ * For more information on content provider testing, please see
+ * <a href="{@docRoot}tools/testing/contentprovider_testing.html">Content Provider Testing</a>.
+ */
+public abstract class ProviderTestCase2<T extends ContentProvider> extends AndroidTestCase {
+
+    Class<T> mProviderClass;
+    String mProviderAuthority;
+
+    private IsolatedContext mProviderContext;
+    private MockContentResolver mResolver;
+
+    private class MockContext2 extends MockContext {
+
+        @Override
+        public Resources getResources() {
+            return getContext().getResources();
+        }
+
+        @Override
+        public File getDir(String name, int mode) {
+            // name the directory so the directory will be separated from
+            // one created through the regular Context
+            return getContext().getDir("mockcontext2_" + name, mode);
+        }
+
+        @Override
+        public Context getApplicationContext() {
+            return this;
+        }
+    }
+    /**
+     * Constructor.
+     *
+     * @param providerClass The class name of the provider under test
+     * @param providerAuthority The provider's authority string
+     */
+    public ProviderTestCase2(Class<T> providerClass, String providerAuthority) {
+        mProviderClass = providerClass;
+        mProviderAuthority = providerAuthority;
+    }
+
+    private T mProvider;
+
+    /**
+     * Returns the content provider created by this class in the {@link #setUp()} method.
+     * @return T An instance of the provider class given as a parameter to the test case class.
+     */
+    public T getProvider() {
+        return mProvider;
+    }
+
+    /**
+     * Sets up the environment for the test fixture.
+     * <p>
+     * Creates a new
+     * {@link android.test.mock.MockContentResolver}, a new IsolatedContext
+     * that isolates the provider's file operations, and a new instance of
+     * the provider under test within the isolated environment.
+     * </p>
+     *
+     * @throws Exception
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mResolver = new MockContentResolver();
+        final String filenamePrefix = "test.";
+        RenamingDelegatingContext targetContextWrapper = new
+                RenamingDelegatingContext(
+                new MockContext2(), // The context that most methods are
+                                    //delegated to
+                getContext(), // The context that file methods are delegated to
+                filenamePrefix);
+        mProviderContext = new IsolatedContext(mResolver, targetContextWrapper);
+        mProvider = createProviderForTest(mProviderContext, mProviderClass, mProviderAuthority);
+        mResolver.addProvider(mProviderAuthority, getProvider());
+    }
+
+    /**
+     * Creates and sets up a new instance of the provider.
+     */
+    static <T extends ContentProvider> T createProviderForTest(
+            Context context, Class<T> providerClass, String authority)
+            throws IllegalAccessException, InstantiationException {
+        T instance = providerClass.newInstance();
+        ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.authority = authority;
+        MockContentProvider.attachInfoForTesting(instance, context, providerInfo);
+        return instance;
+    }
+
+    /**
+     * Tears down the environment for the test fixture.
+     * <p>
+     * Calls {@link android.content.ContentProvider#shutdown()} on the
+     * {@link android.content.ContentProvider} represented by mProvider.
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        mProvider.shutdown();
+        super.tearDown();
+    }
+
+    /**
+     * Gets the {@link MockContentResolver} created by this class during initialization. You
+     * must use the methods of this resolver to access the provider under test.
+     *
+     * @return A {@link MockContentResolver} instance.
+     */
+    public MockContentResolver getMockContentResolver() {
+        return mResolver;
+    }
+
+    /**
+     * Gets the {@link IsolatedContext} created by this class during initialization.
+     * @return The {@link IsolatedContext} instance
+     */
+    public IsolatedContext getMockContext() {
+        return mProviderContext;
+    }
+
+    /**
+     * <p>
+     *      Creates a new content provider of the same type as that passed to the test case class,
+     *      with an authority name set to the authority parameter, and using an SQLite database as
+     *      the underlying data source. The SQL statement parameter is used to create the database.
+     *      This method also creates a new {@link MockContentResolver} and adds the provider to it.
+     * </p>
+     * <p>
+     *      Both the new provider and the new resolver are put into an {@link IsolatedContext}
+     *      that uses the targetContext parameter for file operations and a {@link MockContext}
+     *      for everything else. The IsolatedContext prepends the filenamePrefix parameter to
+     *      file, database, and directory names.
+     * </p>
+     * <p>
+     *      This is a convenience method for creating a "mock" provider that can contain test data.
+     * </p>
+     *
+     * @param targetContext The context to use as the basis of the IsolatedContext
+     * @param filenamePrefix A string that is prepended to file, database, and directory names
+     * @param providerClass The type of the provider being tested
+     * @param authority The authority string to associated with the test provider
+     * @param databaseName The name assigned to the database
+     * @param databaseVersion The version assigned to the database
+     * @param sql A string containing the SQL statements that are needed to create the desired
+     * database and its tables. The format is the same as that generated by the
+     * <a href="http://www.sqlite.org/sqlite.html">sqlite3</a> tool's <code>.dump</code> command.
+     * @return ContentResolver A new {@link MockContentResolver} linked to the provider
+     *
+     * @throws IllegalAccessException
+     * @throws InstantiationException
+     */
+    public static <T extends ContentProvider> ContentResolver newResolverWithContentProviderFromSql(
+            Context targetContext, String filenamePrefix, Class<T> providerClass, String authority,
+            String databaseName, int databaseVersion, String sql)
+            throws IllegalAccessException, InstantiationException {
+        MockContentResolver resolver = new MockContentResolver();
+        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
+                new MockContext(), // The context that most methods are delegated to
+                targetContext, // The context that file methods are delegated to
+                filenamePrefix);
+        Context context = new IsolatedContext(resolver, targetContextWrapper);
+        DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql);
+
+        T provider = createProviderForTest(context, providerClass, authority);
+        resolver.addProvider(authority, provider);
+
+        return resolver;
+    }
+}
diff --git a/android/test/RenamingDelegatingContext.java b/android/test/RenamingDelegatingContext.java
new file mode 100644
index 0000000..10ccebc
--- /dev/null
+++ b/android/test/RenamingDelegatingContext.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.ContentProvider;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.mock.MockContentProvider;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This is a class which delegates to the given context, but performs database
+ * and file operations with a renamed database/file name (prefixes default
+ * names with a given prefix).
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class RenamingDelegatingContext extends ContextWrapper {
+
+    private Context mFileContext;
+    private String mFilePrefix = null;
+    private File mCacheDir;
+    private final Object mSync = new Object();
+
+    private Set<String> mDatabaseNames = new HashSet<>();
+    private Set<String> mFileNames = new HashSet<>();
+
+    public static <T extends ContentProvider> T providerWithRenamedContext(
+            Class<T> contentProvider, Context c, String filePrefix)
+            throws IllegalAccessException, InstantiationException {
+        return providerWithRenamedContext(contentProvider, c, filePrefix, false);
+    }
+
+    public static <T extends ContentProvider> T providerWithRenamedContext(
+            Class<T> contentProvider, Context c, String filePrefix,
+            boolean allowAccessToExistingFilesAndDbs)
+            throws IllegalAccessException, InstantiationException {
+        Class<T> mProviderClass = contentProvider;
+        T mProvider = mProviderClass.newInstance();
+        RenamingDelegatingContext mContext = new RenamingDelegatingContext(c, filePrefix);
+        if (allowAccessToExistingFilesAndDbs) {
+            mContext.makeExistingFilesAndDbsAccessible();
+        }
+        MockContentProvider.attachInfoForTesting(mProvider, mContext, null);
+        return mProvider;
+    }
+
+    /**
+     * Makes accessible all files and databases whose names match the filePrefix that was passed to
+     * the constructor. Normally only files and databases that were created through this context are
+     * accessible.
+     */
+    public void makeExistingFilesAndDbsAccessible() {
+        String[] databaseList = mFileContext.databaseList();
+        for (String diskName : databaseList) {
+            if (shouldDiskNameBeVisible(diskName)) {
+                mDatabaseNames.add(publicNameFromDiskName(diskName));
+            }
+        }
+        String[] fileList = mFileContext.fileList();
+        for (String diskName : fileList) {
+            if (shouldDiskNameBeVisible(diskName)) {
+                mFileNames.add(publicNameFromDiskName(diskName));
+            }
+        }
+    }
+
+    /**
+     * Returns if the given diskName starts with the given prefix or not.
+     * @param diskName name of the database/file.
+     */
+    boolean shouldDiskNameBeVisible(String diskName) {
+        return diskName.startsWith(mFilePrefix);
+    }
+
+    /**
+     * Returns the public name (everything following the prefix) of the given diskName.
+     * @param diskName name of the database/file.
+     */
+    String publicNameFromDiskName(String diskName) {
+        if (!shouldDiskNameBeVisible(diskName)) {
+            throw new IllegalArgumentException("disk file should not be visible: " + diskName);
+        }
+        return diskName.substring(mFilePrefix.length(), diskName.length());
+    }
+
+    /**
+     * @param context : the context that will be delegated.
+     * @param filePrefix : a prefix with which database and file names will be
+     * prefixed.
+     */
+    public RenamingDelegatingContext(Context context, String filePrefix) {
+        super(context);
+        mFileContext = context;
+        mFilePrefix = filePrefix;
+    }
+
+    /**
+     * @param context : the context that will be delegated.
+     * @param fileContext : the context that file and db methods will be delegated to
+     * @param filePrefix : a prefix with which database and file names will be
+     * prefixed.
+     */
+    public RenamingDelegatingContext(Context context, Context fileContext, String filePrefix) {
+        super(context);
+        mFileContext = fileContext;
+        mFilePrefix = filePrefix;
+    }
+
+    public String getDatabasePrefix() {
+        return mFilePrefix;
+    }
+
+    private String renamedFileName(String name) {
+        return mFilePrefix + name;
+    }
+
+    @Override
+    public SQLiteDatabase openOrCreateDatabase(String name,
+            int mode, SQLiteDatabase.CursorFactory factory) {
+        final String internalName = renamedFileName(name);
+        if (!mDatabaseNames.contains(name)) {
+            mDatabaseNames.add(name);
+            mFileContext.deleteDatabase(internalName);
+        }
+        return mFileContext.openOrCreateDatabase(internalName, mode, factory);
+    }
+
+    @Override
+    public SQLiteDatabase openOrCreateDatabase(String name,
+            int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
+        final String internalName = renamedFileName(name);
+        if (!mDatabaseNames.contains(name)) {
+            mDatabaseNames.add(name);
+            mFileContext.deleteDatabase(internalName);
+        }
+        return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler);
+    }
+
+    @Override
+    public boolean deleteDatabase(String name) {
+        if (mDatabaseNames.contains(name)) {
+            mDatabaseNames.remove(name);
+            return mFileContext.deleteDatabase(renamedFileName(name));
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public File getDatabasePath(String name) {
+        return mFileContext.getDatabasePath(renamedFileName(name));
+    }
+
+    @Override
+    public String[] databaseList() {
+        return mDatabaseNames.toArray(new String[]{});
+    }
+
+    @Override
+    public FileInputStream openFileInput(String name)
+            throws FileNotFoundException {
+        final String internalName = renamedFileName(name);
+        if (mFileNames.contains(name)) {
+            return mFileContext.openFileInput(internalName);
+        } else {
+            throw new FileNotFoundException(internalName);
+        }
+    }
+
+    @Override
+    public FileOutputStream openFileOutput(String name, int mode)
+            throws FileNotFoundException {
+        mFileNames.add(name);
+        return mFileContext.openFileOutput(renamedFileName(name), mode);
+    }
+
+    @Override
+    public File getFileStreamPath(String name) {
+        return mFileContext.getFileStreamPath(renamedFileName(name));
+    }
+
+    @Override
+    public boolean deleteFile(String name) {
+        if (mFileNames.contains(name)) {
+            mFileNames.remove(name);
+            return mFileContext.deleteFile(renamedFileName(name));
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public String[] fileList() {
+        return mFileNames.toArray(new String[]{});
+    }
+
+    /**
+     * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
+     * one) and return it instead.  This code is basically getCacheDir(), except it uses the real
+     * cache dir as the parent directory and creates a test cache dir inside that.
+     */
+    @Override
+    public File getCacheDir() {
+        synchronized (mSync) {
+            if (mCacheDir == null) {
+                mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache"));
+            }
+            if (!mCacheDir.exists()) {
+                if(!mCacheDir.mkdirs()) {
+                    Log.w("RenamingDelegatingContext", "Unable to create cache directory");
+                    return null;
+                }
+                try {
+                    // Give the directory all possible permissions.
+                    Files.setPosixFilePermissions(mCacheDir.toPath(),
+                            EnumSet.allOf(PosixFilePermission.class));
+                } catch (IOException e) {
+                    Log.e("RenamingDelegatingContext",
+                            "Could not set permissions of test cacheDir", e);
+                }
+            }
+        }
+        return mCacheDir;
+    }
+}
diff --git a/android/test/RepetitiveTest.java b/android/test/RepetitiveTest.java
new file mode 100644
index 0000000..13e89d2
--- /dev/null
+++ b/android/test/RepetitiveTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used on an {@link android.test.InstrumentationTestCase}'s test methods.
+ * When the annotation is present, the test method is executed the number of times specified by
+ * numIterations and defaults to 1.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RepetitiveTest {
+    /**
+     * Indicates the number of times a test case should be run.
+     *
+     * @return The total number of iterations, the default is 1.
+     */
+    int numIterations() default 1;
+}
diff --git a/android/test/ServiceTestCase.java b/android/test/ServiceTestCase.java
new file mode 100644
index 0000000..cd54955
--- /dev/null
+++ b/android/test/ServiceTestCase.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.app.Application;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.test.mock.MockApplication;
+
+import android.test.mock.MockService;
+import java.util.Random;
+
+/**
+ * This test case provides a framework in which you can test Service classes in
+ * a controlled environment.  It provides basic support for the lifecycle of a
+ * Service, and hooks with which you can inject various dependencies and control
+ * the environment in which your Service is tested.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about application testing, read the
+ * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
+ * </div>
+ *
+ * <p><b>Lifecycle Support.</b>
+ * A Service is accessed with a specific sequence of
+ * calls, as described in the
+ * <a href="http://developer.android.com/guide/topics/fundamentals/services.html">Services</a>
+ * document. In order to support the lifecycle of a Service,
+ * <code>ServiceTestCase</code> enforces this protocol:
+ *
+ * <ul>
+ *      <li>
+ *          The {@link #setUp()} method is called before each test method. The base implementation
+ *          gets the system context. If you override <code>setUp()</code>, you must call
+ *          <code>super.setUp()</code> as the first statement in your override.
+ *      </li>
+ *      <li>
+ *          The test case waits to call {@link android.app.Service#onCreate()} until one of your
+ *          test methods calls {@link #startService} or {@link #bindService}.  This gives you an
+ *          opportunity to set up or adjust any additional framework or test logic before you test
+ *          the running service.
+ *      </li>
+ *      <li>
+ *          When one of your test methods calls {@link #startService ServiceTestCase.startService()}
+ *          or {@link #bindService  ServiceTestCase.bindService()}, the test case calls
+ *          {@link android.app.Service#onCreate() Service.onCreate()} and then calls either
+ *          {@link android.app.Service#startService(Intent) Service.startService(Intent)} or
+ *          {@link android.app.Service#bindService(Intent, ServiceConnection, int)
+ *          Service.bindService(Intent, ServiceConnection, int)}, as appropriate. It also stores
+ *          values needed to track and support the lifecycle.
+ *      </li>
+ *      <li>
+ *          After each test method finishes, the test case calls the {@link #tearDown} method. This
+ *          method stops and destroys the service with the appropriate calls, depending on how the
+ *          service was started. If you override <code>tearDown()</code>, your must call the
+ *          <code>super.tearDown()</code> as the last statement in your override.
+ *      </li>
+ * </ul>
+ *
+ * <p>
+ *      <strong>Dependency Injection.</strong>
+ *      A service has two inherent dependencies, its {@link android.content.Context Context} and its
+ *      associated {@link android.app.Application Application}. The ServiceTestCase framework
+ *      allows you to inject modified, mock, or isolated replacements for these dependencies, and
+ *      thus perform unit tests with controlled dependencies in an isolated environment.
+ * </p>
+ * <p>
+ *      By default, the test case is injected with a full system context and a generic
+ *      {@link android.test.mock.MockApplication MockApplication} object. You can inject
+ *      alternatives to either of these by invoking
+ *      {@link AndroidTestCase#setContext(Context) setContext()} or
+ *      {@link #setApplication setApplication()}.  You must do this <em>before</em> calling
+ *      startService() or bindService().  The test framework provides a
+ *      number of alternatives for Context, including
+ *      {@link android.test.mock.MockContext MockContext},
+ *      {@link android.test.RenamingDelegatingContext RenamingDelegatingContext},
+ *      {@link android.content.ContextWrapper ContextWrapper}, and
+ *      {@link android.test.IsolatedContext}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html">
+ * ServiceTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase {
+
+    Class<T> mServiceClass;
+
+    private Context mSystemContext;
+    private Application mApplication;
+
+    /**
+     * Constructor
+     * @param serviceClass The type of the service under test.
+     */
+    public ServiceTestCase(Class<T> serviceClass) {
+        mServiceClass = serviceClass;
+    }
+
+    private T mService;
+    private boolean mServiceAttached = false;
+    private boolean mServiceCreated = false;
+    private boolean mServiceStarted = false;
+    private boolean mServiceBound = false;
+    private Intent mServiceIntent = null;
+    private int mServiceId;
+
+    /**
+     * @return An instance of the service under test. This instance is created automatically when
+     * a test calls {@link #startService} or {@link #bindService}.
+     */
+    public T getService() {
+        return mService;
+    }
+
+    /**
+     * Gets the current system context and stores it.
+     *
+     * Extend this method to do your own test initialization. If you do so, you
+     * must call <code>super.setUp()</code> as the first statement in your override. The method is
+     * called before each test method is executed.
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // get the real context, before the individual tests have a chance to muck with it
+        mSystemContext = getContext();
+
+    }
+
+    /**
+     * Creates the service under test and attaches all injected dependencies
+     * (Context, Application) to it.  This is called automatically by {@link #startService} or
+     * by {@link #bindService}.
+     * If you need to call {@link AndroidTestCase#setContext(Context) setContext()} or
+     * {@link #setApplication setApplication()}, do so before calling this method.
+     */
+    protected void setupService() {
+        mService = null;
+        try {
+            mService = mServiceClass.newInstance();
+        } catch (Exception e) {
+            assertNotNull(mService);
+        }
+        if (getApplication() == null) {
+            setApplication(new MockApplication());
+        }
+        MockService.attachForTesting(
+                mService, getContext(), mServiceClass.getName(), getApplication());
+
+        assertNotNull(mService);
+
+        mServiceId = new Random().nextInt();
+        mServiceAttached = true;
+    }
+
+    /**
+     * Starts the service under test, in the same way as if it were started by
+     * {@link android.content.Context#startService(Intent) Context.startService(Intent)} with
+     * an {@link android.content.Intent} that identifies a service.
+     * If you use this method to start the service, it is automatically stopped by
+     * {@link #tearDown}.
+     *
+     * @param intent An Intent that identifies a service, of the same form as the Intent passed to
+     * {@link android.content.Context#startService(Intent) Context.startService(Intent)}.
+     */
+    protected void startService(Intent intent) {
+        if (!mServiceAttached) {
+            setupService();
+        }
+        assertNotNull(mService);
+
+        if (!mServiceCreated) {
+            mService.onCreate();
+            mServiceCreated = true;
+        }
+        mService.onStartCommand(intent, 0, mServiceId);
+
+        mServiceStarted = true;
+    }
+
+    /**
+     * <p>
+     *      Starts the service under test, in the same way as if it were started by
+     *      {@link android.content.Context#bindService(Intent, ServiceConnection, int)
+     *      Context.bindService(Intent, ServiceConnection, flags)} with an
+     *      {@link android.content.Intent} that identifies a service.
+     * </p>
+     * <p>
+     *      Notice that the parameters are different. You do not provide a
+     *      {@link android.content.ServiceConnection} object or the flags parameter. Instead,
+     *      you only provide the Intent. The method returns an object whose type is a
+     *      subclass of {@link android.os.IBinder}, or null if the method fails. An IBinder
+     *      object refers to a communication channel between the application and
+     *      the service. The flag is assumed to be {@link android.content.Context#BIND_AUTO_CREATE}.
+     * </p>
+     * <p>
+     *      See <a href="{@docRoot}guide/components/aidl.html">Designing a Remote Interface
+     *      Using AIDL</a> for more information about the communication channel object returned
+     *      by this method.
+     * </p>
+     * Note:  To be able to use bindService in a test, the service must implement getService()
+     * method. An example of this is in the ApiDemos sample application, in the
+     * LocalService demo.
+     *
+     * @param intent An Intent object of the form expected by
+     * {@link android.content.Context#bindService}.
+     *
+     * @return An object whose type is a subclass of IBinder, for making further calls into
+     * the service.
+     */
+    protected IBinder bindService(Intent intent) {
+        if (!mServiceAttached) {
+            setupService();
+        }
+        assertNotNull(mService);
+
+        if (!mServiceCreated) {
+            mService.onCreate();
+            mServiceCreated = true;
+        }
+        // no extras are expected by unbind
+        mServiceIntent = intent.cloneFilter();
+        IBinder result = mService.onBind(intent);
+
+        mServiceBound = true;
+        return result;
+    }
+
+    /**
+     * Makes the necessary calls to stop (or unbind) the service under test, and
+     * calls onDestroy().  Ordinarily this is called automatically (by {@link #tearDown}, but
+     * you can call it directly from your test in order to check for proper shutdown behavior.
+     */
+    protected void shutdownService() {
+        if (mServiceStarted) {
+            mService.stopSelf();
+            mServiceStarted = false;
+        } else if (mServiceBound) {
+            mService.onUnbind(mServiceIntent);
+            mServiceBound = false;
+        }
+        if (mServiceCreated) {
+            mService.onDestroy();
+            mServiceCreated = false;
+        }
+    }
+
+    /**
+     * <p>
+     *      Shuts down the service under test.  Ensures all resources are cleaned up and
+     *      garbage collected before moving on to the next test. This method is called after each
+     *      test method.
+     * </p>
+     * <p>
+     *      Subclasses that override this method must call <code>super.tearDown()</code> as their
+     *      last statement.
+     * </p>
+     *
+     * @throws Exception
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        shutdownService();
+        mService = null;
+
+        // Scrub out members - protects against memory leaks in the case where someone
+        // creates a non-static inner class (thus referencing the test case) and gives it to
+        // someone else to hold onto
+        scrubClass(ServiceTestCase.class);
+
+        super.tearDown();
+    }
+
+    /**
+     * Sets the application that is used during the test.  If you do not call this method,
+     * a new {@link android.test.mock.MockApplication MockApplication} object is used.
+     *
+     * @param application The Application object that is used by the service under test.
+     *
+     * @see #getApplication()
+     */
+    public void setApplication(Application application) {
+        mApplication = application;
+    }
+
+    /**
+     * Returns the Application object in use by the service under test.
+     *
+     * @return The application object.
+     *
+     * @see #setApplication
+     */
+    public Application getApplication() {
+        return mApplication;
+    }
+
+    /**
+     * Returns the real system context that is saved by {@link #setUp()}. Use it to create
+     * mock or other types of context objects for the service under test.
+     *
+     * @return A normal system context.
+     */
+    public Context getSystemContext() {
+        return mSystemContext;
+    }
+
+    /**
+     * Tests that {@link #setupService()} runs correctly and issues an
+     * {@link junit.framework.Assert#assertNotNull(String, Object)} if it does.
+     * You can override this test method if you wish.
+     *
+     * @throws Exception
+     */
+    public void testServiceTestCaseSetUpProperly() throws Exception {
+        setupService();
+        assertNotNull("service should be launched successfully", mService);
+    }
+}
diff --git a/android/test/SimpleCache.java b/android/test/SimpleCache.java
new file mode 100644
index 0000000..46143e4
--- /dev/null
+++ b/android/test/SimpleCache.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Deprecated
+abstract class SimpleCache<K, V> {
+    private Map<K, V> map = new HashMap<K, V>();
+
+    protected abstract V load(K key);
+
+    final V get(K key) {
+        if (map.containsKey(key)) {
+            return map.get(key);
+        }
+        V value = load(key);
+        map.put(key, value);
+        return value;
+    }
+}
diff --git a/android/test/SingleLaunchActivityTestCase.java b/android/test/SingleLaunchActivityTestCase.java
new file mode 100644
index 0000000..af1448e
--- /dev/null
+++ b/android/test/SingleLaunchActivityTestCase.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.app.Activity;
+
+/**
+ * If you would like to test a single activity with an
+ * {@link android.test.InstrumentationTestCase}, this provides some of the boiler plate to
+ * launch and finish the activity in {@link #setUp} and {@link #tearDown}.
+ *
+ * This launches the activity only once for the entire class instead of doing it
+ * in every setup / teardown call.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public abstract class SingleLaunchActivityTestCase<T extends Activity>
+        extends InstrumentationTestCase {
+
+    String mPackage;
+    Class<T> mActivityClass;
+    private static int sTestCaseCounter = 0;
+    private static boolean sActivityLaunchedFlag = false;
+
+    /**
+     * <b>NOTE:</b> The parameter <i>pkg</i> must refer to the package identifier of the
+     * package hosting the activity to be launched, which is specified in the AndroidManifest.xml
+     * file.  This is not necessarily the same as the java package name.
+     *
+     * @param pkg The package hosting the activity to be launched.
+     * @param activityClass The activity to test.
+     */
+    public SingleLaunchActivityTestCase(String pkg, Class<T> activityClass) {
+        mPackage = pkg;
+        mActivityClass = activityClass;
+        sTestCaseCounter ++;
+    }
+
+    /**
+     * The activity that will be set up for use in each test method.
+     */
+    private static Activity sActivity;
+
+    public T getActivity() {
+        return (T) sActivity;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // If it is the first test case, launch the activity.
+        if (!sActivityLaunchedFlag) {
+            // by default, not in touch mode
+            getInstrumentation().setInTouchMode(false);
+            sActivity = launchActivity(mPackage, mActivityClass, null);
+            sActivityLaunchedFlag = true;
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // If it is the last test case, call finish on the activity.
+        sTestCaseCounter --;
+        if (sTestCaseCounter == 0) {
+            sActivity.finish();
+        }
+        super.tearDown();
+    }
+
+    public void testActivityTestCaseSetUpProperly() throws Exception {
+        assertNotNull("activity should be launched successfully", sActivity);
+    }
+}
diff --git a/android/test/SyncBaseInstrumentation.java b/android/test/SyncBaseInstrumentation.java
new file mode 100644
index 0000000..de36b4f
--- /dev/null
+++ b/android/test/SyncBaseInstrumentation.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.net.Uri;
+import android.accounts.Account;
+
+/**
+ * If you would like to test sync a single provider with an
+ * {@link InstrumentationTestCase}, this provides some of the boiler plate in {@link #setUp} and
+ * {@link #tearDown}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class SyncBaseInstrumentation extends InstrumentationTestCase {
+    private Context mTargetContext;
+    ContentResolver mContentResolver;
+    private static final int MAX_TIME_FOR_SYNC_IN_MINS = 20;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTargetContext = getInstrumentation().getTargetContext();
+        mContentResolver = mTargetContext.getContentResolver();
+    }
+
+    /**
+     * Syncs the specified provider.
+     * @throws Exception
+     */
+    protected void syncProvider(Uri uri, String accountName, String authority) throws Exception {
+        Bundle extras = new Bundle();
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+        Account account = new Account(accountName, "com.google");
+
+        ContentResolver.requestSync(account, authority, extras);
+        long startTimeInMillis = SystemClock.elapsedRealtime();
+        long endTimeInMillis = startTimeInMillis + MAX_TIME_FOR_SYNC_IN_MINS * 60000;
+
+        int counter = 0;
+        // Making sure race condition does not occur when en entry have been removed from pending
+        // and active tables and loaded in memory (therefore sync might be still in progress)
+        while (counter < 2) {
+            // Sleep for 1 second.
+            Thread.sleep(1000);
+            // Finish test if time to sync has exceeded max time.
+            if (SystemClock.elapsedRealtime() > endTimeInMillis) {
+                break;
+            }
+
+            if (ContentResolver.isSyncActive(account, authority)) {
+                counter = 0;
+                continue;
+            }
+            counter++;
+        }
+    }
+
+    protected void cancelSyncsandDisableAutoSync() {
+        ContentResolver.setMasterSyncAutomatically(false);
+        ContentResolver.cancelSync(null /* all accounts */, null /* all authorities */);
+    }
+}
diff --git a/android/test/TestCaseUtil.java b/android/test/TestCaseUtil.java
new file mode 100644
index 0000000..1562909
--- /dev/null
+++ b/android/test/TestCaseUtil.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import java.util.ArrayList;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.runner.BaseTestRunner;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @hide - This is part of a framework that is under development and should not be used for
+ * active development.
+ */
+@Deprecated
+public class TestCaseUtil {
+
+    private TestCaseUtil() {
+    }
+
+    public static List<? extends Test> getTests(Test test, boolean flatten) {
+        return getTests(test, flatten, new HashSet<Class<?>>());
+    }
+
+    private static List<? extends Test> getTests(Test test, boolean flatten,
+            Set<Class<?>> seen) {
+        List<Test> testCases = new ArrayList<>();
+        if (test != null) {
+
+            Test workingTest = null;
+            /*
+             * If we want to run a single TestCase method only, we must not
+             * invoke the suite() method, because we will run all test methods
+             * of the class then.
+             */
+            if (test instanceof TestCase &&
+                    ((TestCase)test).getName() == null) {
+                workingTest = invokeSuiteMethodIfPossible(test.getClass(),
+                        seen);
+            }
+            if (workingTest == null) {
+                workingTest = test;
+            }
+
+            if (workingTest instanceof TestSuite) {
+                TestSuite testSuite = (TestSuite) workingTest;
+                Enumeration enumeration = testSuite.tests();
+                while (enumeration.hasMoreElements()) {
+                    Test childTest = (Test) enumeration.nextElement();
+                    if (flatten) {
+                        testCases.addAll(getTests(childTest, flatten, seen));
+                    } else {
+                        testCases.add(childTest);
+                    }
+                }
+            } else {
+                testCases.add(workingTest);
+            }
+        }
+        return testCases;
+    }
+
+    static Test invokeSuiteMethodIfPossible(Class testClass,
+            Set<Class<?>> seen) {
+        try {
+            Method suiteMethod = testClass.getMethod(
+                    BaseTestRunner.SUITE_METHODNAME, new Class[0]);
+            /*
+             * Additional check necessary: If a TestCase contains a suite()
+             * method that returns a TestSuite including the TestCase itself,
+             * we need to stop the recursion. We use a set of classes to
+             * remember which classes' suite() methods were already invoked.
+             */
+            if (Modifier.isStatic(suiteMethod.getModifiers())
+                    && !seen.contains(testClass)) {
+                seen.add(testClass);
+                try {
+                    return (Test) suiteMethod.invoke(null, (Object[]) null);
+                } catch (InvocationTargetException e) {
+                    // do nothing
+                } catch (IllegalAccessException e) {
+                    // do nothing
+                }
+            }
+        } catch (NoSuchMethodException e) {
+            // do nothing
+        }
+        return null;
+    }
+
+    static String getTestName(Test test) {
+        if (test instanceof TestCase) {
+            TestCase testCase = (TestCase) test;
+            return testCase.getName();
+        } else if (test instanceof TestSuite) {
+            TestSuite testSuite = (TestSuite) test;
+            String name = testSuite.getName();
+            if (name != null) {
+                int index = name.lastIndexOf(".");
+                if (index > -1) {
+                    return name.substring(index + 1);
+                } else {
+                    return name;
+                }
+            }
+        }
+        return "";
+    }
+}
diff --git a/android/test/TestPrinter.java b/android/test/TestPrinter.java
new file mode 100644
index 0000000..01d392d
--- /dev/null
+++ b/android/test/TestPrinter.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2006 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.test;
+
+import android.util.Log;
+import junit.framework.Test;
+import junit.framework.TestListener;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Prints the test progress to stdout. Android includes a default
+ * implementation and calls these methods to print out test progress; you
+ * probably will not need to create or extend this class or call its methods manually.
+ * See the full {@link android.test} package description for information about
+ * getting test results.
+ *
+ * {@hide} Not needed for 1.0 SDK.
+ */
+@Deprecated
+class TestPrinter implements TestListener {
+
+    private String mTag;
+    private boolean mOnlyFailures;
+    private Set<String> mFailedTests = new HashSet<String>();
+
+
+    TestPrinter(String tag, boolean onlyFailures) {
+        mTag = tag;
+        mOnlyFailures = onlyFailures;
+    }
+
+    private void started(String className) {
+        if (!mOnlyFailures) {
+            Log.i(mTag, "started: " + className);
+        }
+    }
+
+    private void finished(String className) {
+        if (!mOnlyFailures) {
+            Log.i(mTag, "finished: " + className);
+        }
+    }
+
+    private void passed(String className) {
+        if (!mOnlyFailures) {
+            Log.i(mTag, "passed: " + className);
+        }
+    }
+
+    private void failed(String className, Throwable exception) {
+        Log.i(mTag, "failed: " + className);
+        Log.i(mTag, "----- begin exception -----");
+        Log.i(mTag, "", exception);
+        Log.i(mTag, "----- end exception -----");
+    }
+
+    private void failed(Test test, Throwable t) {
+        mFailedTests.add(test.toString());
+        failed(test.toString(), t);
+    }
+
+    public void addError(Test test, Throwable t) {
+        failed(test, t);
+    }
+
+    public void addFailure(Test test, junit.framework.AssertionFailedError t) {
+        failed(test, t);
+    }
+
+    public void endTest(Test test) {
+        finished(test.toString());
+        if (!mFailedTests.contains(test.toString())) {
+            passed(test.toString());
+        }
+        mFailedTests.remove(test.toString());
+    }
+
+    public void startTest(Test test) {
+        started(test.toString());
+    }
+}
diff --git a/android/test/TestSuiteProvider.java b/android/test/TestSuiteProvider.java
new file mode 100644
index 0000000..12cfcb7
--- /dev/null
+++ b/android/test/TestSuiteProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import junit.framework.TestSuite;
+
+/**
+ * Implementors will know how to get a test suite.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public interface TestSuiteProvider {
+
+    TestSuite getTestSuite();
+}
diff --git a/android/test/TouchUtils.java b/android/test/TouchUtils.java
new file mode 100644
index 0000000..f2f0be7
--- /dev/null
+++ b/android/test/TouchUtils.java
@@ -0,0 +1,834 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+/**
+ * Reusable methods for generating touch events. These methods can be used with
+ * InstrumentationTestCase or ActivityInstrumentationTestCase2 to simulate user interaction with
+ * the application through a touch screen.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso UI testing
+ * framework</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class TouchUtils {
+
+    /**
+     * Simulate touching in the center of the screen and dragging one quarter of the way down
+     * @param test The test case that is being run
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) {
+        dragQuarterScreenDown(test, test.getActivity());
+    }
+
+    /**
+     * Simulate touching in the center of the screen and dragging one quarter of the way down
+     * @param test The test case that is being run
+     * @param activity The activity that is in the foreground of the test case
+     */
+    public static void dragQuarterScreenDown(InstrumentationTestCase test, Activity activity) {
+        Display display = activity.getWindowManager().getDefaultDisplay();
+        final Point size = new Point();
+        display.getSize(size);
+
+        final float x = size.x / 2.0f;
+        final float fromY = size.y * 0.5f;
+        final float toY = size.y * 0.75f;
+
+        drag(test, x, x, fromY, toY, 4);
+    }
+
+    /**
+     * Simulate touching in the center of the screen and dragging one quarter of the way up
+     * @param test The test case that is being run
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) {
+        dragQuarterScreenUp(test, test.getActivity());
+    }
+
+    /**
+     * Simulate touching in the center of the screen and dragging one quarter of the way up
+     * @param test The test case that is being run
+     * @param activity The activity that is in the foreground of the test case
+     */
+    public static void dragQuarterScreenUp(InstrumentationTestCase test, Activity activity) {
+        Display display = activity.getWindowManager().getDefaultDisplay();
+        final Point size = new Point();
+        display.getSize(size);
+
+        final float x = size.x / 2.0f;
+        final float fromY = size.y * 0.5f;
+        final float toY = size.y * 0.25f;
+
+        drag(test, x, x, fromY, toY, 4);
+    }
+
+    /**
+     * Scroll a ViewGroup to the bottom by repeatedly calling
+     * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
+     *
+     * @param test The test case that is being run
+     * @param v The ViewGroup that should be dragged
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) {
+        scrollToBottom(test, test.getActivity(), v);
+    }
+
+    /**
+     * Scroll a ViewGroup to the bottom by repeatedly calling
+     * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
+     *
+     * @param test The test case that is being run
+     * @param activity The activity that is in the foreground of the test case
+     * @param v The ViewGroup that should be dragged
+     */
+    public static void scrollToBottom(InstrumentationTestCase test, Activity activity,
+            ViewGroup v) {
+        ViewStateSnapshot prev;
+        ViewStateSnapshot next = new ViewStateSnapshot(v);
+        do {
+            prev = next;
+            TouchUtils.dragQuarterScreenUp(test, activity);
+            next = new ViewStateSnapshot(v);
+        } while (!prev.equals(next));
+    }
+
+    /**
+     * Scroll a ViewGroup to the top by repeatedly calling
+     * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
+     *
+     * @param test The test case that is being run
+     * @param v The ViewGroup that should be dragged
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) {
+        scrollToTop(test, test.getActivity(), v);
+    }
+
+    /**
+     * Scroll a ViewGroup to the top by repeatedly calling
+     * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
+     *
+     * @param test The test case that is being run
+     * @param activity The activity that is in the foreground of the test case
+     * @param v The ViewGroup that should be dragged
+     */
+    public static void scrollToTop(InstrumentationTestCase test, Activity activity, ViewGroup v) {
+        ViewStateSnapshot prev;
+        ViewStateSnapshot next = new ViewStateSnapshot(v);
+        do {
+            prev = next;
+            TouchUtils.dragQuarterScreenDown(test, activity);
+            next = new ViewStateSnapshot(v);
+        } while (!prev.equals(next));
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the bottom of the screen.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) {
+        dragViewToBottom(test, test.getActivity(), v, 4);
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the bottom of the screen.
+     *
+     * @param test The test case that is being run
+     * @param activity The activity that is in the foreground of the test case
+     * @param v The view that should be dragged
+     */
+    public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v) {
+        dragViewToBottom(test, activity, v, 4);
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the bottom of the screen.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param stepCount How many move steps to include in the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v,
+            int stepCount) {
+        dragViewToBottom(test, test.getActivity(), v, stepCount);
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the bottom of the screen.
+     *
+     * @param test The test case that is being run
+     * @param activity The activity that is in the foreground of the test case
+     * @param v The view that should be dragged
+     * @param stepCount How many move steps to include in the drag
+     */
+    public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v,
+            int stepCount) {
+        int screenHeight =
+                activity.getWindowManager().getCurrentWindowMetrics().getBounds().height();
+
+        int[] xy = new int[2];
+        v.getLocationOnScreen(xy);
+
+        final int viewWidth = v.getWidth();
+        final int viewHeight = v.getHeight();
+
+        final float x = xy[0] + (viewWidth / 2.0f);
+        float fromY = xy[1] + (viewHeight / 2.0f);
+        float toY = screenHeight - 1;
+
+        drag(test, x, x, fromY, toY, stepCount);
+    }
+
+    /**
+     * Simulate touching the center of a view and releasing quickly (before the tap timeout).
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be clicked
+     */
+    public static void tapView(InstrumentationTestCase test, View v) {
+        int[] xy = new int[2];
+        v.getLocationOnScreen(xy);
+
+        final int viewWidth = v.getWidth();
+        final int viewHeight = v.getHeight();
+
+        final float x = xy[0] + (viewWidth / 2.0f);
+        float y = xy[1] + (viewHeight / 2.0f);
+
+        Instrumentation inst = test.getInstrumentation();
+
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+        eventTime = SystemClock.uptimeMillis();
+        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
+                x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+    }
+
+    /**
+     * Simulate touching the center of a view and cancelling (so no onClick should
+     * fire, etc).
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be clicked
+     */
+    public static void touchAndCancelView(InstrumentationTestCase test, View v) {
+        int[] xy = new int[2];
+        v.getLocationOnScreen(xy);
+
+        final int viewWidth = v.getWidth();
+        final int viewHeight = v.getHeight();
+
+        final float x = xy[0] + (viewWidth / 2.0f);
+        float y = xy[1] + (viewHeight / 2.0f);
+
+        Instrumentation inst = test.getInstrumentation();
+
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+        eventTime = SystemClock.uptimeMillis();
+        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL,
+                x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+    }
+
+    /**
+     * Simulate touching the center of a view and releasing.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be clicked
+     */
+    public static void clickView(InstrumentationTestCase test, View v) {
+        int[] xy = new int[2];
+        v.getLocationOnScreen(xy);
+
+        final int viewWidth = v.getWidth();
+        final int viewHeight = v.getHeight();
+
+        final float x = xy[0] + (viewWidth / 2.0f);
+        float y = xy[1] + (viewHeight / 2.0f);
+
+        Instrumentation inst = test.getInstrumentation();
+
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+
+        eventTime = SystemClock.uptimeMillis();
+        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
+                x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Simulate touching the center of a view, holding until it is a long press, and then releasing.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be clicked
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void longClickView(ActivityInstrumentationTestCase test, View v) {
+        longClickView((InstrumentationTestCase) test, v);
+    }
+
+    /**
+     * Simulate touching the center of a view, holding until it is a long press, and then releasing.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be clicked
+     */
+    public static void longClickView(InstrumentationTestCase test, View v) {
+        int[] xy = new int[2];
+        v.getLocationOnScreen(xy);
+
+        final int viewWidth = v.getWidth();
+        final int viewHeight = v.getHeight();
+
+        final float x = xy[0] + (viewWidth / 2.0f);
+        float y = xy[1] + (viewHeight / 2.0f);
+
+        Instrumentation inst = test.getInstrumentation();
+
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+        eventTime = SystemClock.uptimeMillis();
+        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
+                x + touchSlop / 2, y + touchSlop / 2, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+
+        try {
+            Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the top of the screen.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) {
+        dragViewToTop((InstrumentationTestCase) test, v, 4);
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the top of the screen.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param stepCount How many move steps to include in the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) {
+        dragViewToTop((InstrumentationTestCase) test, v, stepCount);
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the top of the screen.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     */
+    public static void dragViewToTop(InstrumentationTestCase test, View v) {
+        dragViewToTop(test, v, 4);
+    }
+
+    /**
+     * Simulate touching the center of a view and dragging to the top of the screen.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param stepCount How many move steps to include in the drag
+     */
+    public static void dragViewToTop(InstrumentationTestCase test, View v, int stepCount) {
+        int[] xy = new int[2];
+        v.getLocationOnScreen(xy);
+
+        final int viewWidth = v.getWidth();
+        final int viewHeight = v.getHeight();
+
+        final float x = xy[0] + (viewWidth / 2.0f);
+        float fromY = xy[1] + (viewHeight / 2.0f);
+        float toY = 0;
+
+        drag(test, x, x, fromY, toY, stepCount);
+    }
+
+    /**
+     * Get the location of a view. Use the gravity param to specify which part of the view to
+     * return.
+     *
+     * @param v View to find
+     * @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL,
+     *        RIGHT)
+     * @param xy Result
+     */
+    private static void getStartLocation(View v, int gravity, int[] xy) {
+        v.getLocationOnScreen(xy);
+
+        final int viewWidth = v.getWidth();
+        final int viewHeight = v.getHeight();
+
+        switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
+        case Gravity.TOP:
+            break;
+        case Gravity.CENTER_VERTICAL:
+            xy[1] += viewHeight / 2;
+            break;
+        case Gravity.BOTTOM:
+            xy[1] += viewHeight - 1;
+            break;
+        default:
+            // Same as top -- do nothing
+        }
+
+        switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+        case Gravity.LEFT:
+            break;
+        case Gravity.CENTER_HORIZONTAL:
+            xy[0] += viewWidth / 2;
+            break;
+        case Gravity.RIGHT:
+            xy[0] += viewWidth - 1;
+            break;
+        default:
+            // Same as left -- do nothing
+        }
+    }
+
+    /**
+     * Simulate touching a view and dragging it by the specified amount.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param deltaX Amount to drag horizontally in pixels
+     * @param deltaY Amount to drag vertically in pixels
+     *
+     * @return distance in pixels covered by the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static int dragViewBy(ActivityInstrumentationTestCase test, View v, int gravity,
+            int deltaX, int deltaY) {
+        return dragViewBy((InstrumentationTestCase) test, v, gravity, deltaX, deltaY);
+    }
+
+    /**
+     * Simulate touching a view and dragging it by the specified amount.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param deltaX Amount to drag horizontally in pixels
+     * @param deltaY Amount to drag vertically in pixels
+     *
+     * @return distance in pixels covered by the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX,
+            int deltaY) {
+        int[] xy = new int[2];
+
+        getStartLocation(v, gravity, xy);
+
+        final int fromX = xy[0];
+        final int fromY = xy[1];
+
+        int distance = (int) Math.hypot(deltaX, deltaY);
+
+        drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance);
+
+        return distance;
+    }
+
+    /**
+     * Simulate touching a view and dragging it to a specified location.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param toX Final location of the view after dragging
+     * @param toY Final location of the view after dragging
+     *
+     * @return distance in pixels covered by the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static int dragViewTo(ActivityInstrumentationTestCase test, View v, int gravity, int toX,
+            int toY) {
+        return dragViewTo((InstrumentationTestCase) test, v, gravity, toX, toY);
+    }
+
+    /**
+     * Simulate touching a view and dragging it to a specified location.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param toX Final location of the view after dragging
+     * @param toY Final location of the view after dragging
+     *
+     * @return distance in pixels covered by the drag
+     */
+    public static int dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX,
+            int toY) {
+        int[] xy = new int[2];
+
+        getStartLocation(v, gravity, xy);
+
+        final int fromX = xy[0];
+        final int fromY = xy[1];
+
+        int deltaX = fromX - toX;
+        int deltaY = fromY - toY;
+
+        int distance = (int)Math.hypot(deltaX, deltaY);
+        drag(test, fromX, toX, fromY, toY, distance);
+
+        return distance;
+    }
+
+    /**
+     * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param toX Final location of the view after dragging
+     *
+     * @return distance in pixels covered by the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static int dragViewToX(ActivityInstrumentationTestCase test, View v, int gravity,
+            int toX) {
+        return dragViewToX((InstrumentationTestCase) test, v, gravity, toX);
+    }
+
+    /**
+     * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param toX Final location of the view after dragging
+     *
+     * @return distance in pixels covered by the drag
+     */
+    public static int dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX) {
+        int[] xy = new int[2];
+
+        getStartLocation(v, gravity, xy);
+
+        final int fromX = xy[0];
+        final int fromY = xy[1];
+
+        int deltaX = fromX - toX;
+
+        drag(test, fromX, toX, fromY, fromY, deltaX);
+
+        return deltaX;
+    }
+
+    /**
+     * Simulate touching a view and dragging it to a specified location. Only moves vertically.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param toY Final location of the view after dragging
+     *
+     * @return distance in pixels covered by the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static int dragViewToY(ActivityInstrumentationTestCase test, View v, int gravity,
+            int toY) {
+        return dragViewToY((InstrumentationTestCase) test, v, gravity, toY);
+    }
+
+    /**
+     * Simulate touching a view and dragging it to a specified location. Only moves vertically.
+     *
+     * @param test The test case that is being run
+     * @param v The view that should be dragged
+     * @param gravity Which part of the view to use for the initial down event. A combination of
+     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
+     * @param toY Final location of the view after dragging
+     *
+     * @return distance in pixels covered by the drag
+     */
+    public static int dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY) {
+        int[] xy = new int[2];
+
+        getStartLocation(v, gravity, xy);
+
+        final int fromX = xy[0];
+        final int fromY = xy[1];
+
+        int deltaY = fromY - toY;
+
+        drag(test, fromX, fromX, fromY, toY, deltaY);
+
+        return deltaY;
+    }
+
+
+    /**
+     * Simulate touching a specific location and dragging to a new location.
+     *
+     * @param test The test case that is being run
+     * @param fromX X coordinate of the initial touch, in screen coordinates
+     * @param toX Xcoordinate of the drag destination, in screen coordinates
+     * @param fromY X coordinate of the initial touch, in screen coordinates
+     * @param toY Y coordinate of the drag destination, in screen coordinates
+     * @param stepCount How many move steps to include in the drag
+     *
+     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
+     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
+     * configuring the Activity under test
+     */
+    @Deprecated
+    public static void drag(ActivityInstrumentationTestCase test, float fromX, float toX,
+            float fromY, float toY, int stepCount) {
+        drag((InstrumentationTestCase) test, fromX, toX, fromY, toY, stepCount);
+    }
+
+    /**
+     * Simulate touching a specific location and dragging to a new location.
+     *
+     * @param test The test case that is being run
+     * @param fromX X coordinate of the initial touch, in screen coordinates
+     * @param toX Xcoordinate of the drag destination, in screen coordinates
+     * @param fromY X coordinate of the initial touch, in screen coordinates
+     * @param toY Y coordinate of the drag destination, in screen coordinates
+     * @param stepCount How many move steps to include in the drag
+     */
+    public static void drag(InstrumentationTestCase test, float fromX, float toX, float fromY,
+            float toY, int stepCount) {
+        Instrumentation inst = test.getInstrumentation();
+
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        float y = fromY;
+        float x = fromX;
+
+        float yStep = (toY - fromY) / stepCount;
+        float xStep = (toX - fromX) / stepCount;
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        inst.sendPointerSync(event);
+        for (int i = 0; i < stepCount; ++i) {
+            y += yStep;
+            x += xStep;
+            eventTime = SystemClock.uptimeMillis();
+            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+            inst.sendPointerSync(event);
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        inst.sendPointerSync(event);
+        inst.waitForIdleSync();
+    }
+
+    private static class ViewStateSnapshot {
+        final View mFirst;
+        final View mLast;
+        final int mFirstTop;
+        final int mLastBottom;
+        final int mChildCount;
+        private ViewStateSnapshot(ViewGroup viewGroup) {
+            mChildCount = viewGroup.getChildCount();
+            if (mChildCount == 0) {
+                mFirst = mLast = null;
+                mFirstTop = mLastBottom = Integer.MIN_VALUE;
+            } else {
+                mFirst = viewGroup.getChildAt(0);
+                mLast = viewGroup.getChildAt(mChildCount - 1);
+                mFirstTop = mFirst.getTop();
+                mLastBottom = mLast.getBottom();
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final ViewStateSnapshot that = (ViewStateSnapshot) o;
+            return mFirstTop == that.mFirstTop &&
+                    mLastBottom == that.mLastBottom &&
+                    mFirst == that.mFirst &&
+                    mLast == that.mLast &&
+                    mChildCount == that.mChildCount;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mFirst != null ? mFirst.hashCode() : 0;
+            result = 31 * result + (mLast != null ? mLast.hashCode() : 0);
+            result = 31 * result + mFirstTop;
+            result = 31 * result + mLastBottom;
+            result = 31 * result + mChildCount;
+            return result;
+        }
+    }
+}
diff --git a/android/test/UiThreadTest.java b/android/test/UiThreadTest.java
new file mode 100644
index 0000000..cd06ab8
--- /dev/null
+++ b/android/test/UiThreadTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * This annotation can be used on an {@link InstrumentationTestCase}'s test methods.
+ * When the annotation is present, the test method is executed on the application's
+ * main thread (or UI thread.) Note that instrumentation methods may not be used
+ * when this annotation is present.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/annotation/UiThreadTest.html">
+ * UiThreadTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UiThreadTest {
+}
diff --git a/android/test/ViewAsserts.java b/android/test/ViewAsserts.java
new file mode 100644
index 0000000..00ab443
--- /dev/null
+++ b/android/test/ViewAsserts.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import static junit.framework.Assert.*;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Some useful assertions about views.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">Espresso
+ * View Matchers</a> instead. New test should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ * For more information about UI testing, take the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Espresso UI testing</a> training.
+ */
+@Deprecated
+public class ViewAsserts {
+
+    private ViewAsserts() {}
+
+    /**
+     * Assert that view is on the screen.
+     * @param origin The root view of the screen.
+     * @param view The view.
+     */
+    static public void assertOnScreen(View origin, View view) {
+        int[] xy = new int[2];
+        view.getLocationOnScreen(xy);
+
+        int[] xyRoot = new int[2];
+        origin.getLocationOnScreen(xyRoot);
+
+        int y = xy[1] - xyRoot[1];
+
+        assertTrue("view should have positive y coordinate on screen",
+                y  >= 0);
+
+        assertTrue("view should have y location on screen less than drawing "
+                + "height of root view",
+                y <= view.getRootView().getHeight());
+    }
+
+    /**
+     * Assert that view is below the visible screen.
+     * @param origin The root view of the screen.
+     * @param view The view
+     */
+    static public void assertOffScreenBelow(View origin, View view) {
+        int[] xy = new int[2];
+        view.getLocationOnScreen(xy);
+
+        int[] xyRoot = new int[2];
+        origin.getLocationOnScreen(xyRoot);
+
+        int y = xy[1] - xyRoot[1];
+
+        assertTrue("view should have y location on screen greater than drawing "
+                + "height of origen view (" + y + " is not greater than "
+                + origin.getHeight() + ")",
+                y > origin.getHeight());
+    }
+
+    /**
+     * Assert that view is above the visible screen.
+     * @param origin Te root view of the screen.
+     * @param view The view
+     */
+    static public void assertOffScreenAbove(View origin, View view) {
+        int[] xy = new int[2];
+        view.getLocationOnScreen(xy);
+
+        int[] xyRoot = new int[2];
+        origin.getLocationOnScreen(xyRoot);
+
+        int y = xy[1] - xyRoot[1];
+
+        assertTrue("view should have y location less than that of origin view",
+                y < 0);
+    }
+
+    /**
+     * Assert that a view has a particular x and y position on the visible screen.
+     * @param origin The root view of the screen.
+     * @param view The view.
+     * @param x The expected x coordinate.
+     * @param y The expected y coordinate.
+     */
+    static public void assertHasScreenCoordinates(View origin, View view, int x, int y) {
+        int[] xy = new int[2];
+        view.getLocationOnScreen(xy);
+
+        int[] xyRoot = new int[2];
+        origin.getLocationOnScreen(xyRoot);
+
+        assertEquals("x coordinate", x, xy[0] - xyRoot[0]);
+        assertEquals("y coordinate", y, xy[1] - xyRoot[1]);
+    }
+
+    /**
+     * Assert that two views are aligned on their baseline, that is that their baselines
+     * are on the same y location.
+     *
+     * @param first The first view
+     * @param second The second view
+     */
+    static public void assertBaselineAligned(View first, View second) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstTop = xy[1] + first.getBaseline();
+
+        second.getLocationOnScreen(xy);
+        int secondTop = xy[1] + second.getBaseline();
+
+        assertEquals("views are not baseline aligned", firstTop, secondTop);
+    }
+
+    /**
+     * Assert that two views are right aligned, that is that their right edges
+     * are on the same x location.
+     *
+     * @param first The first view
+     * @param second The second view
+     */
+    static public void assertRightAligned(View first, View second) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstRight = xy[0] + first.getMeasuredWidth();
+
+        second.getLocationOnScreen(xy);
+        int secondRight = xy[0] + second.getMeasuredWidth();
+
+        assertEquals("views are not right aligned", firstRight, secondRight);
+    }
+
+    /**
+     * Assert that two views are right aligned, that is that their right edges
+     * are on the same x location, with respect to the specified margin.
+     *
+     * @param first The first view
+     * @param second The second view
+     * @param margin The margin between the first view and the second view
+     */
+    static public void assertRightAligned(View first, View second, int margin) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstRight = xy[0] + first.getMeasuredWidth();
+
+        second.getLocationOnScreen(xy);
+        int secondRight = xy[0] + second.getMeasuredWidth();
+
+        assertEquals("views are not right aligned", Math.abs(firstRight - secondRight), margin);
+    }
+
+    /**
+     * Assert that two views are left aligned, that is that their left edges
+     * are on the same x location.
+     *
+     * @param first The first view
+     * @param second The second view
+     */
+    static public void assertLeftAligned(View first, View second) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstLeft = xy[0];
+
+        second.getLocationOnScreen(xy);
+        int secondLeft = xy[0];
+
+        assertEquals("views are not left aligned", firstLeft, secondLeft);
+    }
+
+    /**
+     * Assert that two views are left aligned, that is that their left edges
+     * are on the same x location, with respect to the specified margin.
+     *
+     * @param first The first view
+     * @param second The second view
+     * @param margin The margin between the first view and the second view
+     */
+    static public void assertLeftAligned(View first, View second, int margin) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstLeft = xy[0];
+
+        second.getLocationOnScreen(xy);
+        int secondLeft = xy[0];
+
+        assertEquals("views are not left aligned", Math.abs(firstLeft - secondLeft), margin);
+    }
+
+    /**
+     * Assert that two views are bottom aligned, that is that their bottom edges
+     * are on the same y location.
+     *
+     * @param first The first view
+     * @param second The second view
+     */
+    static public void assertBottomAligned(View first, View second) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstBottom = xy[1] + first.getMeasuredHeight();
+
+        second.getLocationOnScreen(xy);
+        int secondBottom = xy[1] + second.getMeasuredHeight();
+
+        assertEquals("views are not bottom aligned", firstBottom, secondBottom);
+    }
+
+    /**
+     * Assert that two views are bottom aligned, that is that their bottom edges
+     * are on the same y location, with respect to the specified margin.
+     *
+     * @param first The first view
+     * @param second The second view
+     * @param margin The margin between the first view and the second view
+     */
+    static public void assertBottomAligned(View first, View second, int margin) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstBottom = xy[1] + first.getMeasuredHeight();
+
+        second.getLocationOnScreen(xy);
+        int secondBottom = xy[1] + second.getMeasuredHeight();
+
+        assertEquals("views are not bottom aligned", Math.abs(firstBottom - secondBottom), margin);
+    }
+
+    /**
+     * Assert that two views are top aligned, that is that their top edges
+     * are on the same y location.
+     *
+     * @param first The first view
+     * @param second The second view
+     */
+    static public void assertTopAligned(View first, View second) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstTop = xy[1];
+
+        second.getLocationOnScreen(xy);
+        int secondTop = xy[1];
+
+        assertEquals("views are not top aligned", firstTop, secondTop);
+    }
+
+    /**
+     * Assert that two views are top aligned, that is that their top edges
+     * are on the same y location, with respect to the specified margin.
+     *
+     * @param first The first view
+     * @param second The second view
+     * @param margin The margin between the first view and the second view
+     */
+    static public void assertTopAligned(View first, View second, int margin) {
+        int[] xy = new int[2];
+        first.getLocationOnScreen(xy);
+        int firstTop = xy[1];
+
+        second.getLocationOnScreen(xy);
+        int secondTop = xy[1];
+
+        assertEquals("views are not top aligned", Math.abs(firstTop - secondTop), margin);
+    }
+
+    /**
+     * Assert that the <code>test</code> view is horizontally center aligned
+     * with respect to the <code>reference</code> view.
+     *
+     * @param reference The reference view
+     * @param test The view that should be center aligned with the reference view
+     */
+    static public void assertHorizontalCenterAligned(View reference, View test) {
+        int[] xy = new int[2];
+        reference.getLocationOnScreen(xy);
+        int referenceLeft = xy[0];
+
+        test.getLocationOnScreen(xy);
+        int testLeft = xy[0];
+
+        int center = (reference.getMeasuredWidth() - test.getMeasuredWidth()) / 2;
+        int delta = testLeft - referenceLeft;
+
+        assertEquals("views are not horizontally center aligned", center, delta);
+    }
+
+    /**
+     * Assert that the <code>test</code> view is vertically center aligned
+     * with respect to the <code>reference</code> view.
+     *
+     * @param reference The reference view
+     * @param test The view that should be center aligned with the reference view
+     */
+    static public void assertVerticalCenterAligned(View reference, View test) {
+        int[] xy = new int[2];
+        reference.getLocationOnScreen(xy);
+        int referenceTop = xy[1];
+
+        test.getLocationOnScreen(xy);
+        int testTop = xy[1];
+
+        int center = (reference.getMeasuredHeight() - test.getMeasuredHeight()) / 2;
+        int delta = testTop - referenceTop;
+
+        assertEquals("views are not vertically center aligned", center, delta);
+    }
+
+    /**
+     * Assert the specified group's integrity. The children count should be >= 0 and each
+     * child should be non-null.
+     *
+     * @param parent The group whose integrity to check
+     */
+    static public void assertGroupIntegrity(ViewGroup parent) {
+        final int count = parent.getChildCount();
+        assertTrue("child count should be >= 0", count >= 0);
+
+        for (int i = 0; i < count; i++) {
+            assertNotNull("group should not contain null children", parent.getChildAt(i));
+            assertSame(parent, parent.getChildAt(i).getParent());
+        }
+    }
+
+    /**
+     * Assert that the specified group contains a specific child once and only once.
+     *
+     * @param parent The group
+     * @param child The child that should belong to group
+     */
+    static public void assertGroupContains(ViewGroup parent, View child) {
+        final int count = parent.getChildCount();
+        assertTrue("Child count should be >= 0", count >= 0);
+
+        boolean found = false;
+        for (int i = 0; i < count; i++) {
+            if (parent.getChildAt(i) == child) {
+                if (!found) {
+                    found = true;
+                } else {
+                    assertTrue("child " + child + " is duplicated in parent", false);
+                }
+            }
+        }
+
+        assertTrue("group does not contain " + child, found);
+    }
+
+    /**
+     * Assert that the specified group does not contain a specific child.
+     *
+     * @param parent The group
+     * @param child The child that should not belong to group
+     */
+    static public void assertGroupNotContains(ViewGroup parent, View child) {
+        final int count = parent.getChildCount();
+        assertTrue("Child count should be >= 0", count >= 0);
+
+        for (int i = 0; i < count; i++) {
+            if (parent.getChildAt(i) == child) {
+                assertTrue("child " + child + " is found in parent", false);
+            }
+        }
+    }
+}
diff --git a/android/test/mock/MockAccountManager.java b/android/test/mock/MockAccountManager.java
new file mode 100644
index 0000000..c9b4c7b
--- /dev/null
+++ b/android/test/mock/MockAccountManager.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 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.test.mock;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OnAccountsUpdateListener;
+import android.accounts.OperationCanceledException;
+import android.content.Context;
+import android.os.Handler;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A mock {@link android.accounts.AccountManager} class.
+ *
+ * <p>Provided for use by {@code android.test.IsolatedContext}.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}
+ * tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class MockAccountManager {
+
+    /**
+     * Create a new mock {@link AccountManager} instance.
+     *
+     * @param context the {@link Context} to which the returned object belongs.
+     * @return the new instance.
+     */
+    public static AccountManager newMockAccountManager(Context context) {
+        return new MockAccountManagerImpl(context);
+    }
+
+    private MockAccountManager() {
+    }
+
+    private static class MockAccountManagerImpl extends AccountManager {
+
+        MockAccountManagerImpl(Context context) {
+            super(context, null /* IAccountManager */, null /* handler */);
+        }
+
+        public void addOnAccountsUpdatedListener(OnAccountsUpdateListener listener,
+                Handler handler, boolean updateImmediately) {
+            // do nothing
+        }
+
+        public Account[] getAccounts() {
+            return new Account[] {};
+        }
+
+        public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
+                final String type, final String[] features,
+                AccountManagerCallback<Account[]> callback, Handler handler) {
+            return new MockAccountManagerFuture<Account[]>(new Account[0]);
+        }
+
+        public String blockingGetAuthToken(Account account, String authTokenType,
+                boolean notifyAuthFailure)
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            return null;
+        }
+    }
+
+    /**
+     * A very simple AccountManagerFuture class
+     * that returns what ever was passed in
+     */
+    private static class MockAccountManagerFuture<T>
+            implements AccountManagerFuture<T> {
+
+        T mResult;
+
+        MockAccountManagerFuture(T result) {
+            mResult = result;
+        }
+
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            return false;
+        }
+
+        public boolean isCancelled() {
+            return false;
+        }
+
+        public boolean isDone() {
+            return true;
+        }
+
+        public T getResult()
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            return mResult;
+        }
+
+        public T getResult(long timeout, TimeUnit unit)
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            return getResult();
+        }
+    }
+}
diff --git a/android/test/mock/MockApplication.java b/android/test/mock/MockApplication.java
new file mode 100644
index 0000000..3257ecf
--- /dev/null
+++ b/android/test/mock/MockApplication.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.mock;
+
+import android.app.Application;
+import android.content.res.Configuration;
+
+/**
+ * A mock {@link android.app.Application} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}.  Override it as necessary to provide the
+ * operations that you need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class MockApplication extends Application {
+
+    public MockApplication() {
+    }
+
+    @Override
+    public void onCreate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onTerminate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/android/test/mock/MockContentProvider.java b/android/test/mock/MockContentProvider.java
new file mode 100644
index 0000000..d1d64d3
--- /dev/null
+++ b/android/test/mock/MockContentProvider.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2009 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.test.mock;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentProvider;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.content.pm.PathPermission;
+import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * Mock implementation of ContentProvider.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}.  Tests can extend this class to
+ * implement behavior needed for tests.
+ */
+public class MockContentProvider extends ContentProvider {
+    /*
+     * Note: if you add methods to ContentProvider, you must add similar methods to
+     *       MockContentProvider.
+     */
+
+    /**
+     * IContentProvider that directs all calls to this MockContentProvider.
+     */
+    private class InversionIContentProvider implements IContentProvider {
+        @Override
+        public ContentProviderResult[] applyBatch(String callingPackage,
+                @Nullable String featureId, String authority,
+                ArrayList<ContentProviderOperation> operations)
+                throws RemoteException, OperationApplicationException {
+            return MockContentProvider.this.applyBatch(authority, operations);
+        }
+
+        @Override
+        public int bulkInsert(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues[] initialValues) throws RemoteException {
+            return MockContentProvider.this.bulkInsert(url, initialValues);
+        }
+
+        @Override
+        public int delete(String callingPackage, @Nullable String featureId, Uri url,
+                Bundle extras) throws RemoteException {
+            return MockContentProvider.this.delete(url, extras);
+        }
+
+        @Override
+        public String getType(Uri url) throws RemoteException {
+            return MockContentProvider.this.getType(url);
+        }
+
+        @Override
+        public void getTypeAsync(Uri uri, RemoteCallback callback) throws RemoteException {
+            MockContentProvider.this.getTypeAsync(uri, callback);
+        }
+
+        @Override
+        public Uri insert(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues initialValues, Bundle extras) throws RemoteException {
+            return MockContentProvider.this.insert(url, initialValues, extras);
+        }
+
+        @Override
+        public AssetFileDescriptor openAssetFile(String callingPackage,
+                @Nullable String featureId, Uri url, String mode, ICancellationSignal signal)
+                throws RemoteException, FileNotFoundException {
+            return MockContentProvider.this.openAssetFile(url, mode);
+        }
+
+        @Override
+        public ParcelFileDescriptor openFile(String callingPackage, @Nullable String featureId,
+                Uri url, String mode, ICancellationSignal signal, IBinder callerToken)
+                throws RemoteException, FileNotFoundException {
+            return MockContentProvider.this.openFile(url, mode);
+        }
+
+        @Override
+        public Cursor query(String callingPackage, @Nullable String featureId, Uri url,
+                @Nullable String[] projection, @Nullable Bundle queryArgs,
+                @Nullable ICancellationSignal cancellationSignal) throws RemoteException {
+            return MockContentProvider.this.query(url, projection, queryArgs, null);
+        }
+
+        @Override
+        public int update(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues values, Bundle extras) throws RemoteException {
+            return MockContentProvider.this.update(url, values, extras);
+        }
+
+        @Override
+        public Bundle call(String callingPackage, @Nullable String featureId, String authority,
+                String method, String request, Bundle args) throws RemoteException {
+            return MockContentProvider.this.call(authority, method, request, args);
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return MockContentProvider.this.getIContentProviderBinder();
+        }
+
+        @Override
+        public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
+            return MockContentProvider.this.getStreamTypes(url, mimeTypeFilter);
+        }
+
+        @Override
+        public AssetFileDescriptor openTypedAssetFile(String callingPackage,
+                @Nullable String featureId, Uri url, String mimeType, Bundle opts,
+                ICancellationSignal signal) throws RemoteException, FileNotFoundException {
+            return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
+        }
+
+        @Override
+        public ICancellationSignal createCancellationSignal() throws RemoteException {
+            return null;
+        }
+
+        @Override
+        public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+                throws RemoteException {
+            return MockContentProvider.this.canonicalize(uri);
+        }
+
+        @Override
+        public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+                RemoteCallback callback) {
+            MockContentProvider.this.canonicalizeAsync(uri, callback);
+        }
+
+        @Override
+        public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+                throws RemoteException {
+            return MockContentProvider.this.uncanonicalize(uri);
+        }
+
+        @Override
+        public boolean refresh(String callingPkg, @Nullable String featureId, Uri url,
+                Bundle args, ICancellationSignal cancellationSignal) throws RemoteException {
+            return MockContentProvider.this.refresh(url, args);
+        }
+
+        @Override
+        public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri,
+                int uid, int modeFlags) {
+            return MockContentProvider.this.checkUriPermission(uri, uid, modeFlags);
+        }
+    }
+    private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
+
+    /**
+     * A constructor using {@link MockContext} instance as a Context in it.
+     */
+    protected MockContentProvider() {
+        super(new MockContext(), "", "", null);
+    }
+
+    /**
+     * A constructor accepting a Context instance, which is supposed to be the subclasss of
+     * {@link MockContext}.
+     */
+    public MockContentProvider(Context context) {
+        super(context, "", "", null);
+    }
+
+    /**
+     * A constructor which initialize four member variables which
+     * {@link android.content.ContentProvider} have internally.
+     *
+     * @param context A Context object which should be some mock instance (like the
+     * instance of {@link android.test.mock.MockContext}).
+     * @param readPermission The read permision you want this instance should have in the
+     * test, which is available via {@link #getReadPermission()}.
+     * @param writePermission The write permission you want this instance should have
+     * in the test, which is available via {@link #getWritePermission()}.
+     * @param pathPermissions The PathPermissions you want this instance should have
+     * in the test, which is available via {@link #getPathPermissions()}.
+     */
+    public MockContentProvider(Context context,
+            String readPermission,
+            String writePermission,
+            PathPermission[] pathPermissions) {
+        super(context, readPermission, writePermission, pathPermissions);
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    /**
+     * @hide
+     */
+    @SuppressWarnings("deprecation")
+    public void getTypeAsync(Uri uri, RemoteCallback remoteCallback) {
+        AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+            final Bundle bundle = new Bundle();
+            bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
+            remoteCallback.sendResult(bundle);
+        });
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean onCreate() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    /**
+     * If you're reluctant to implement this manually, please just call super.bulkInsert().
+     */
+    @Override
+    public int bulkInsert(Uri uri, ContentValues[] values) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public Bundle call(String method, String request, Bundle args) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+
+    @Override
+    public String[] getStreamTypes(Uri url, String mimeTypeFilter) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+
+    @Override
+    public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+
+    /**
+     * @hide
+     */
+    @SuppressWarnings("deprecation")
+    public void canonicalizeAsync(Uri uri, RemoteCallback callback) {
+        AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+            final Bundle bundle = new Bundle();
+            bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, canonicalize(uri));
+            callback.sendResult(bundle);
+        });
+    }
+
+    /**
+     * @hide
+     */
+    public boolean refresh(Uri url, Bundle args) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+
+    /** {@hide} */
+    @Override
+    public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+
+    /**
+     * Returns IContentProvider which calls back same methods in this class.
+     * By overriding this class, we avoid the mechanism hidden behind ContentProvider
+     * (IPC, etc.)
+     *
+     * @hide
+     */
+    @Override
+    public final IContentProvider getIContentProvider() {
+        return mIContentProvider;
+    }
+
+    /**
+     * @hide
+     */
+    public IBinder getIContentProviderBinder() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    /**
+     * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use
+     * when directly instantiating the provider for testing.
+     *
+     * <p>Provided for use by {@code android.test.ProviderTestCase2} and
+     * {@code android.test.RenamingDelegatingContext}.
+     *
+     * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+     * New tests should be written using the
+     * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+     */
+    @Deprecated
+    public static void attachInfoForTesting(
+            ContentProvider provider, Context context, ProviderInfo providerInfo) {
+        provider.attachInfoForTesting(context, providerInfo);
+    }
+}
diff --git a/android/test/mock/MockContentResolver.java b/android/test/mock/MockContentResolver.java
new file mode 100644
index 0000000..8f4bccc
--- /dev/null
+++ b/android/test/mock/MockContentResolver.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.mock;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.database.ContentObserver;
+import android.net.Uri;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>
+ *      An extension of {@link android.content.ContentResolver} that is designed for
+ *      testing.
+ * </p>
+ * <p>
+ *      MockContentResolver overrides Android's normal way of resolving providers by
+ *      authority. To have access to a provider based on its authority, users of
+ *      MockContentResolver first instantiate the provider and
+ *      use {@link MockContentResolver#addProvider(String, ContentProvider)}. Resolution of an
+ *      authority occurs entirely within MockContentResolver.
+ * </p>
+ * <p>
+ *      Users can also set an authority's entry in the map to null, so that a provider is completely
+ *      mocked out.
+ * </p>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about application testing, read the
+ * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
+ * </div>
+ */
+public class MockContentResolver extends ContentResolver {
+    Map<String, ContentProvider> mProviders;
+
+    /**
+     * Creates a local map of providers. This map is used instead of the global
+     * map when an API call tries to acquire a provider.
+     */
+    public MockContentResolver() {
+        this(null);
+    }
+
+    /**
+     * Creates a local map of providers. This map is used instead of the global
+     * map when an API call tries to acquire a provider.
+     */
+    public MockContentResolver(Context context) {
+        super(context);
+        mProviders = new HashMap<>();
+    }
+
+    /**
+     * Adds access to a provider based on its authority
+     *
+     * @param name The authority name associated with the provider.
+     * @param provider An instance of {@link android.content.ContentProvider} or one of its
+     * subclasses, or null.
+     */
+    public void addProvider(String name, ContentProvider provider) {
+
+        /*
+         * Maps the authority to the provider locally.
+         */
+        mProviders.put(name, provider);
+    }
+
+    /** @hide */
+    @Override
+    protected IContentProvider acquireProvider(Context context, String name) {
+        return acquireExistingProvider(context, name);
+    }
+
+    /** @hide */
+    @Override
+    protected IContentProvider acquireExistingProvider(Context context, String name) {
+
+        /*
+         * Gets the content provider from the local map
+         */
+        final ContentProvider provider = mProviders.get(name);
+
+        if (provider != null) {
+            return provider.getIContentProvider();
+        } else {
+            return null;
+        }
+    }
+
+    /** @hide */
+    @Override
+    public boolean releaseProvider(IContentProvider provider) {
+        return true;
+    }
+
+    /** @hide */
+    @Override
+    protected IContentProvider acquireUnstableProvider(Context c, String name) {
+        return acquireProvider(c, name);
+    }
+
+    /** @hide */
+    @Override
+    public boolean releaseUnstableProvider(IContentProvider icp) {
+        return releaseProvider(icp);
+    }
+
+    /** @hide */
+    @Override
+    public void unstableProviderDied(IContentProvider icp) {
+    }
+
+    /**
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
+     */
+    @Override
+    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
+    }
+
+    /**
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
+     *
+     * @deprecated callers should consider migrating to
+     *             {@link #notifyChange(Uri, ContentObserver, int)}, as it
+     *             offers support for many more options than just
+     *             {@link #NOTIFY_SYNC_TO_NETWORK}.
+     */
+    @Override
+    @Deprecated
+    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
+            boolean syncToNetwork) {
+    }
+
+    /**
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
+     */
+    @Override
+    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
+            @NotifyFlags int flags) {
+    }
+
+    /**
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
+     */
+    @Override
+    public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer,
+            @NotifyFlags int flags) {
+    }
+}
diff --git a/android/test/mock/MockContext.java b/android/test/mock/MockContext.java
new file mode 100644
index 0000000..cf3b03c
--- /dev/null
+++ b/android/test/mock/MockContext.java
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2007 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.test.mock;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.view.Display;
+import android.view.DisplayAdjustments;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.Executor;
+
+/**
+ * A mock {@link android.content.Context} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}.  You can use this to inject other dependencies,
+ * mocks, or monitors into the classes you are testing.
+ */
+public class MockContext extends Context {
+
+    @Override
+    public AssetManager getAssets() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Resources getResources() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PackageManager getPackageManager() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ContentResolver getContentResolver() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Looper getMainLooper() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Executor getMainExecutor() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTheme(int resid) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Resources.Theme getTheme() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ClassLoader getClassLoader() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getPackageName() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public String getBasePackageName() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public String getOpPackageName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ApplicationInfo getApplicationInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getPackageResourcePath() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getPackageCodePath() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SharedPreferences getSharedPreferences(String name, int mode) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @removed */
+    @Override
+    public SharedPreferences getSharedPreferences(File file, int mode) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void reloadSharedPreferences() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean deleteSharedPreferences(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FileInputStream openFileInput(String name) throws FileNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean deleteFile(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getFileStreamPath(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @removed */
+    @Override
+    public File getSharedPreferencesPath(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String[] fileList() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getDataDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getFilesDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc Context#getCrateDir()}
+     * @hide
+     */
+    @Override
+    public File getCrateDir(@NonNull String crateId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getNoBackupFilesDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getExternalFilesDir(String type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getObbDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getCacheDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getCodeCacheDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getExternalCacheDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getDir(String name, int mode) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SQLiteDatabase openOrCreateDatabase(String file, int mode,
+            SQLiteDatabase.CursorFactory factory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SQLiteDatabase openOrCreateDatabase(String file, int mode,
+            SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getDatabasePath(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String[] databaseList() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean moveDatabaseFrom(Context sourceContext, String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean deleteDatabase(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getWallpaper() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable peekWallpaper() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getWallpaperDesiredMinimumWidth() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getWallpaperDesiredMinimumHeight() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setWallpaper(Bitmap bitmap) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setWallpaper(InputStream data) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void clearWallpaper() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startActivity(Intent intent) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startActivity(Intent intent, Bundle options) {
+        startActivity(intent);
+    }
+
+    @Override
+    public void startActivities(Intent[] intents) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startActivities(Intent[] intents, Bundle options) {
+        startActivities(intents);
+    }
+
+    @Override
+    public void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
+            Bundle options) throws IntentSender.SendIntentException {
+        startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags);
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent, String receiverPermission) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+            String[] receiverPermissions) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @SystemApi
+    @Override
+    public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent,
+            String receiverPermission) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
+           Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @SystemApi
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
+           Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @SystemApi
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcast(Intent intent, int initialCode, String receiverPermission,
+            String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+            String initialData, Bundle initialExtras, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendStickyBroadcast(Intent intent) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendStickyOrderedBroadcast(Intent intent,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
+           Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeStickyBroadcast(Intent intent) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendStickyOrderedBroadcastAsUser(Intent intent,
+            UserHandle user, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+            int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+            String broadcastPermission, Handler scheduler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+            String broadcastPermission, Handler scheduler, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    @SystemApi
+    public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterReceiver(BroadcastReceiver receiver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ComponentName startService(Intent service) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ComponentName startForegroundService(Intent service) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean stopService(Intent service) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean stopServiceAsUser(Intent service, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean bindService(Intent service, int flags, Executor executor,
+            ServiceConnection conn) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean bindIsolatedService(Intent service, int flags, String instanceName,
+            Executor executor, ServiceConnection conn) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+            UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void updateServiceGroup(ServiceConnection conn, int group, int importance) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unbindService(ServiceConnection conn) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean startInstrumentation(ComponentName className,
+            String profileFile, Bundle arguments) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkPermission(String permission, int pid, int uid) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+        return checkPermission(permission, pid, uid);
+    }
+
+    @Override
+    public int checkCallingPermission(String permission) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkCallingOrSelfPermission(String permission) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkSelfPermission(String permission) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enforcePermission(
+            String permission, int pid, int uid, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enforceCallingPermission(String permission, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enforceCallingOrSelfPermission(String permission, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void revokeUriPermission(Uri uri, int modeFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void revokeUriPermission(String targetPackage, Uri uri, int modeFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+        return checkUriPermission(uri, pid, uid, modeFlags);
+    }
+
+    @Override
+    public int checkCallingUriPermission(Uri uri, int modeFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkUriPermission(Uri uri, String readPermission,
+            String writePermission, int pid, int uid, int modeFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enforceUriPermission(
+            Uri uri, int pid, int uid, int modeFlags, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enforceCallingUriPermission(
+            Uri uri, int modeFlags, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enforceCallingOrSelfUriPermission(
+            Uri uri, int modeFlags, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void enforceUriPermission(
+            Uri uri, String readPermission, String writePermission,
+            int pid, int uid, int modeFlags, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Context createPackageContext(String packageName, int flags)
+            throws PackageManager.NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public Context createApplicationContext(ApplicationInfo application, int flags)
+            throws PackageManager.NameNotFoundException {
+        return null;
+    }
+
+    /** @hide */
+    @Override
+    public Context createContextForSplit(String splitName)
+            throws PackageManager.NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
+            throws PackageManager.NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public int getUserId() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Context createConfigurationContext(Configuration overrideConfiguration) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Context createDisplayContext(Display display) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public @NonNull Context createWindowContext(int type, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isRestricted() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public DisplayAdjustments getDisplayAdjustments(int displayId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Display getDisplay() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public Display getDisplayNoVerify() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int getDisplayId() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void updateDisplay(int displayId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File[] getExternalFilesDirs(String type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File[] getObbDirs() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File[] getExternalCacheDirs() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File[] getExternalMediaDirs() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide **/
+    @Override
+    public File getPreloadsFileCache() { throw new UnsupportedOperationException(); }
+
+    @Override
+    public Context createDeviceProtectedStorageContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @SystemApi
+    @Override
+    public Context createCredentialProtectedStorageContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isDeviceProtectedStorage() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @SystemApi
+    @Override
+    public boolean isCredentialProtectedStorage() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public boolean canLoadUnsafeResources() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public IBinder getActivityToken() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+            int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public IApplicationThread getIApplicationThread() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public Handler getMainThreadHandler() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public boolean isUiContext() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/android/test/mock/MockCursor.java b/android/test/mock/MockCursor.java
new file mode 100644
index 0000000..f69db2c
--- /dev/null
+++ b/android/test/mock/MockCursor.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2009 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.test.mock;
+
+import android.content.ContentResolver;
+import android.database.CharArrayBuffer;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.List;
+
+/**
+ * A mock {@link android.database.Cursor} class that isolates the test code from real
+ * Cursor implementation.
+ *
+ * <p>
+ * All methods including ones related to querying the state of the cursor are
+ * are non-functional and throw {@link java.lang.UnsupportedOperationException}.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class MockCursor implements Cursor {
+    @Override
+    public int getColumnCount() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int getColumnIndex(String columnName) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int getColumnIndexOrThrow(String columnName) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public String getColumnName(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public String[] getColumnNames() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int getCount() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean isNull(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int getInt(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public long getLong(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public short getShort(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public float getFloat(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public double getDouble(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public byte[] getBlob(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public String getString(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void setExtras(Bundle extras) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Bundle getExtras() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int getPosition() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean isAfterLast() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean isBeforeFirst() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean isFirst() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean isLast() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean move(int offset) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean moveToFirst() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean moveToLast() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean moveToNext() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean moveToPrevious() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean moveToPosition(int position) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    @Deprecated
+    public void deactivate() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void close() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean isClosed() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    @Deprecated
+    public boolean requery() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void registerContentObserver(ContentObserver observer) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Bundle respond(Bundle extras) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean getWantsAllOnMoveCalls() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void setNotificationUri(ContentResolver cr, Uri uri) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void setNotificationUris(ContentResolver cr, List<Uri> uris) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Uri getNotificationUri() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public List<Uri> getNotificationUris() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void unregisterContentObserver(ContentObserver observer) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int getType(int columnIndex) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+}
\ No newline at end of file
diff --git a/android/test/mock/MockDialogInterface.java b/android/test/mock/MockDialogInterface.java
new file mode 100644
index 0000000..d0a5a09
--- /dev/null
+++ b/android/test/mock/MockDialogInterface.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.mock;
+
+import android.content.DialogInterface;
+
+/**
+ * A mock {@link android.content.DialogInterface} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
+ * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class MockDialogInterface implements DialogInterface {
+    public void cancel() {
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    public void dismiss() {
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+}
diff --git a/android/test/mock/MockIContentProvider.java b/android/test/mock/MockIContentProvider.java
new file mode 100644
index 0000000..223bcc5
--- /dev/null
+++ b/android/test/mock/MockIContentProvider.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2009 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.test.mock;
+
+import android.annotation.Nullable;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.EntityIterator;
+import android.content.IContentProvider;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * Mock implementation of IContentProvider.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}.  Tests can extend this class to
+ * implement behavior needed for tests.
+ *
+ * @hide - @hide because this exposes bulkQuery() and call(), which must also be hidden.
+ */
+public class MockIContentProvider implements IContentProvider {
+    @Override
+    public int bulkInsert(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues[] initialValues) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    @SuppressWarnings("unused")
+    public int delete(String callingPackage, @Nullable String featureId, Uri url,
+            Bundle extras) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public String getType(Uri url) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void getTypeAsync(Uri uri, RemoteCallback remoteCallback) {
+        AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+            final Bundle bundle = new Bundle();
+            bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
+            remoteCallback.sendResult(bundle);
+        });
+    }
+
+    @Override
+    @SuppressWarnings("unused")
+    public Uri insert(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues initialValues, Bundle extras) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(String callingPackage, @Nullable String featureId,
+            Uri url, String mode, ICancellationSignal signal, IBinder callerToken) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public AssetFileDescriptor openAssetFile(String callingPackage, @Nullable String featureId,
+            Uri uri, String mode, ICancellationSignal signal) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public ContentProviderResult[] applyBatch(String callingPackage, @Nullable String featureId,
+            String authority, ArrayList<ContentProviderOperation> operations) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Cursor query(String callingPackage, @Nullable String featureId, Uri url,
+            @Nullable String[] projection, @Nullable Bundle queryArgs,
+            @Nullable ICancellationSignal cancellationSignal) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
+            String sortOrder) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public int update(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues values, Bundle extras) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Bundle call(String callingPackage, @Nullable String featureId, String authority,
+            String method, String request, Bundle args) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public IBinder asBinder() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public AssetFileDescriptor openTypedAssetFile(String callingPackage,
+            @Nullable String featureId, Uri url, String mimeType, Bundle opts,
+            ICancellationSignal signal) throws RemoteException, FileNotFoundException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public ICancellationSignal createCancellationSignal() throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+            RemoteCallback remoteCallback) {
+        AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+            final Bundle bundle = new Bundle();
+            bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+                    canonicalize(callingPkg, featureId, uri));
+            remoteCallback.sendResult(bundle);
+        });
+    }
+
+    @Override
+    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
+    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle args,
+            ICancellationSignal cancellationSignal) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    /** {@hide} */
+    @Override
+    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri, int uid,
+            int modeFlags) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+}
diff --git a/android/test/mock/MockPackageManager.java b/android/test/mock/MockPackageManager.java
new file mode 100644
index 0000000..5f95bc1
--- /dev/null
+++ b/android/test/mock/MockPackageManager.java
@@ -0,0 +1,1252 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.mock;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ChangedPackages;
+import android.content.pm.FeatureInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstantAppInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.KeySet;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.os.storage.VolumeInfo;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A mock {@link android.content.pm.PackageManager} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
+ * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class MockPackageManager extends PackageManager {
+
+    @Override
+    public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PackageInfo getPackageInfo(VersionedPackage versionedPackage,
+            int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String[] currentToCanonicalPackageNames(String[] names) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String[] canonicalToCurrentPackageNames(String[] names) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Intent getLaunchIntentForPackage(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public Intent getCarLaunchIntentForPackage(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int[] getPackageGids(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int getPackageUidAsUser(String packageName, int flags, int userHandle)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int getPackageUidAsUser(String packageName, int userHandle)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PermissionInfo getPermissionInfo(String name, int flags)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean arePermissionsIndividuallyControlled() {
+        return false;
+    }
+
+    /** @hide */
+    @Override
+    public boolean isWirelessConsentModeEnabled() {
+        return false;
+    }
+
+    @Override
+    public PermissionGroupInfo getPermissionGroupInfo(String name,
+            int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ApplicationInfo getApplicationInfo(String packageName, int flags)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public ApplicationInfo getApplicationInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ActivityInfo getActivityInfo(ComponentName className, int flags)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ActivityInfo getReceiverInfo(ComponentName className, int flags)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServiceInfo getServiceInfo(ComponentName className, int flags)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ProviderInfo getProviderInfo(ComponentName className, int flags)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PackageInfo> getInstalledPackages(int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PackageInfo> getPackagesHoldingPermissions(String[] permissions,
+            int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkPermission(String permName, String pkgName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean canRequestPackageInstalls() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isPermissionRevokedByPolicy(String permName, String pkgName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public String getPermissionControllerPackageName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean addPermission(PermissionInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean addPermissionAsync(PermissionInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removePermission(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void grantRuntimePermission(String packageName, String permissionName,
+            UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void revokeRuntimePermission(String packageName, String permissionName,
+            UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int getPermissionFlags(String permissionName, String packageName, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void updatePermissionFlags(String permissionName, String packageName,
+            int flagMask, int flagValues, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public @NonNull Set<String> getWhitelistedRestrictedPermissions(
+            @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean shouldShowRequestPermissionRationale(String permission) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkSignatures(String pkg1, String pkg2) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int checkSignatures(int uid1, int uid2) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String[] getPackagesForUid(int uid) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getNameForUid(int uid) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public String[] getNamesForUids(int uid[]) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public int getUidForSharedUser(String sharedUserName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ApplicationInfo> getInstalledApplications(int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public List<InstantAppInfo> getInstantApps() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public Drawable getInstantAppIcon(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public byte[] getInstantAppCookie() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean isInstantApp() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean isInstantApp(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int getInstantAppCookieMaxBytes() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int getInstantAppCookieMaxSize() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void clearInstantAppCookie() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void updateInstantAppCookie(@NonNull byte[] cookie) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean setInstantAppCookie(@NonNull byte[] cookie) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public ChangedPackages getChangedPackages(int sequenceNumber) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ResolveInfo resolveActivity(Intent intent, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
+                                                   int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
+            Intent[] specifics, Intent intent, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ResolveInfo resolveService(Intent intent, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ResolveInfo resolveServiceAsUser(Intent intent, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public List<ResolveInfo> queryIntentContentProvidersAsUser(
+            Intent intent, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ProviderInfo resolveContentProvider(String name, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ProviderInfo> queryContentProviders(String processName, int uid, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<InstrumentationInfo> queryInstrumentation(
+            String targetPackage, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getDrawable(String packageName, int resid, ApplicationInfo appInfo) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityIcon(ComponentName activityName)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityIcon(Intent intent) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getDefaultActivityIcon() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityBanner(ComponentName activityName)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityBanner(Intent intent) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationBanner(ApplicationInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationBanner(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationIcon(ApplicationInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationIcon(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityLogo(ComponentName activityName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityLogo(Intent intent) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationLogo(ApplicationInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationLogo(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getUserBadgedDrawableForDensity(Drawable drawable, UserHandle user,
+            Rect badgeLocation,
+            int badgeDensity) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public Drawable getUserBadgeForDensity(UserHandle user, int density) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CharSequence getText(String packageName, int resid, ApplicationInfo appInfo) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public XmlResourceParser getXml(String packageName, int resid,
+            ApplicationInfo appInfo) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CharSequence getApplicationLabel(ApplicationInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Resources getResourcesForActivity(ComponentName activityName)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Resources getResourcesForApplication(ApplicationInfo app) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Resources getResourcesForApplication(String appPackageName)
+    throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public Resources getResourcesForApplicationAsUser(String appPackageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setInstallerPackageName(String targetPackage,
+            String installerPackageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void setUpdateAvailable(String packageName, boolean updateAvailable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getInstallerPackageName(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public int getMoveStatus(int moveId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public void registerMoveCallback(MoveCallback callback, Handler handler) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public void unregisterMoveCallback(MoveCallback callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public int movePackage(String packageName, VolumeInfo vol) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public VolumeInfo getPackageCurrentVolume(ApplicationInfo app) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public int movePrimaryStorage(VolumeInfo vol) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public VolumeInfo getPrimaryStorageCurrentVolume() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public List<VolumeInfo> getPrimaryStorageCandidateVolumes() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void clearApplicationUserData(
+            String packageName, IPackageDataObserver observer) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void deleteApplicationCacheFiles(
+            String packageName, IPackageDataObserver observer) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void deleteApplicationCacheFilesAsUser(String packageName, int userId,
+            IPackageDataObserver observer) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public void freeStorageAndNotify(String volumeUuid, long idealStorageSize,
+            IPackageDataObserver observer) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public void freeStorage(String volumeUuid, long idealStorageSize, IntentSender pi) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
+            int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addPackageToPreferred(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removePackageFromPreferred(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PackageInfo> getPreferredPackages(int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setComponentEnabledSetting(ComponentName componentName,
+            int newState, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getComponentEnabledSetting(ComponentName componentName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setApplicationEnabledSetting(String packageName, int newState, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getApplicationEnabledSetting(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void flushPackageRestrictionsAsUser(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addPreferredActivity(IntentFilter filter,
+            int match, ComponentName[] set, ComponentName activity) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void replacePreferredActivity(IntentFilter filter,
+            int match, ComponentName[] set, ComponentName activity) {
+        throw new UnsupportedOperationException();
+    }
+
+
+    @Override
+    public void clearPackagePreferredActivities(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void getPackageSizeInfoAsUser(String packageName, int userHandle,
+            IPackageStatsObserver observer) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getPreferredActivities(List<IntentFilter> outFilters,
+            List<ComponentName> outActivities, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide - hidden in superclass */
+    @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String[] getSystemSharedLibraryNames() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public @NonNull List<SharedLibraryInfo> getSharedLibraries(int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public @NonNull String getServicesSystemSharedLibraryPackageName() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public @NonNull String getSharedSystemSharedLibraryPackageName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FeatureInfo[] getSystemAvailableFeatures() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasSystemFeature(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasSystemFeature(String name, int version) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isSafeMode() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public KeySet getKeySetByAlias(String packageName, String alias) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public KeySet getSigningKeySet(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean isSignedBy(String packageName, KeySet ks) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean isSignedByExactly(String packageName, KeySet ks) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public String[] setPackagesSuspended(String[] packageNames, boolean hidden,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean isPackageSuspendedForUser(String packageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void setApplicationCategoryHint(String packageName, int categoryHint) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
+            UserHandle user) {
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean getApplicationHiddenSettingAsUser(String packageName, UserHandle user) {
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int installExistingPackage(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int installExistingPackage(String packageName, int installReason)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int installExistingPackageAsUser(String packageName, int userId)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void verifyPendingInstall(int id, int verificationCode) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+            long millisecondsToDelay) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int getIntentVerificationStatusAsUser(String packageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<IntentFilter> getAllIntentFilters(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@removed} */
+    @Deprecated
+    public String getDefaultBrowserPackageName(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public String getDefaultBrowserPackageNameAsUser(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@removed} */
+    @Deprecated
+    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public VerifierDeviceIdentity getVerifierDeviceIdentity() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean isUpgrade() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean isDeviceUpgrading() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
+            int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearCrossProfileIntentFilters(int sourceUserId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    public PackageInstaller getPackageInstaller() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public boolean isPackageAvailable(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    public int getInstallReason(String packageName, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public ComponentName getInstantAppResolverSettingsComponent() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public ComponentName getInstantAppInstallerComponent() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    public String getInstantAppAndroidId(String packageName, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void registerDexModule(String dexModulePath,
+            @Nullable DexModuleRegisterCallback callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public ArtManager getArtManager() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setHarmfulAppWarning(String packageName, CharSequence warning) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public CharSequence getHarmfulAppWarning(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasSigningCertificate(
+            String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasSigningCertificate(
+            int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/android/test/mock/MockResources.java b/android/test/mock/MockResources.java
new file mode 100644
index 0000000..880343e
--- /dev/null
+++ b/android/test/mock/MockResources.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.mock;
+
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.content.res.ColorStateList;
+import android.content.res.XmlResourceParser;
+import android.content.res.AssetFileDescriptor;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.util.AttributeSet;
+import android.graphics.drawable.Drawable;
+import android.graphics.Movie;
+
+import java.io.InputStream;
+
+/**
+ * A mock {@link android.content.res.Resources} class. All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
+ * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class MockResources extends Resources {
+
+    public MockResources() {
+        super(new AssetManager(), null, null);
+    }
+
+    @Override
+    public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
+        // this method is called from the constructor, so we just do nothing
+    }
+
+    @Override
+    public CharSequence getText(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public CharSequence getQuantityText(int id, int quantity) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getString(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getString(int id, Object... formatArgs) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getQuantityString(int id, int quantity, Object... formatArgs)
+            throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getQuantityString(int id, int quantity) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public CharSequence getText(int id, CharSequence def) {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public CharSequence[] getTextArray(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String[] getStringArray(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public int[] getIntArray(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public TypedArray obtainTypedArray(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public float getDimension(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public int getDimensionPixelOffset(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public int getDimensionPixelSize(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public Drawable getDrawable(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public Movie getMovie(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public int getColor(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public ColorStateList getColorStateList(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public int getInteger(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public XmlResourceParser getLayout(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public XmlResourceParser getAnimation(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public XmlResourceParser getXml(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public InputStream openRawResource(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public void getValue(int id, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public void getValue(String name, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public DisplayMetrics getDisplayMetrics() {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public Configuration getConfiguration() {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public int getIdentifier(String name, String defType, String defPackage) {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getResourceName(int resid) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getResourcePackageName(int resid) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getResourceTypeName(int resid) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+
+    @Override
+    public String getResourceEntryName(int resid) throws NotFoundException {
+        throw new UnsupportedOperationException("mock object, not implemented");
+    }
+}
diff --git a/android/test/mock/MockService.java b/android/test/mock/MockService.java
new file mode 100644
index 0000000..dbba4f3
--- /dev/null
+++ b/android/test/mock/MockService.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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.test.mock;
+
+import android.app.Application;
+import android.app.Service;
+import android.content.Context;
+
+/**
+ * A mock {@link android.app.Service} class.
+ *
+ * <p>Provided for use by {@code android.test.ServiceTestCase}.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class MockService {
+
+    public static <T extends Service> void attachForTesting(Service service, Context context,
+            String serviceClassName,
+            Application application) {
+        service.attach(
+                context,
+                null,               // ActivityThread not actually used in Service
+                serviceClassName,
+                null,               // token not needed when not talking with the activity manager
+                application,
+                null                // mocked services don't talk with the activity manager
+        );
+    }
+
+    private MockService() {
+    }
+}
diff --git a/android/test/suitebuilder/AssignableFrom.java b/android/test/suitebuilder/AssignableFrom.java
new file mode 100644
index 0000000..84db066
--- /dev/null
+++ b/android/test/suitebuilder/AssignableFrom.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import com.android.internal.util.Predicate;
+
+class AssignableFrom implements Predicate<TestMethod> {
+
+    private final Class<?> root;
+
+    AssignableFrom(Class<?> root) {
+        this.root = root;
+    }
+
+    public boolean apply(TestMethod testMethod) {
+        return root.isAssignableFrom(testMethod.getEnclosingClass());
+    }
+}
diff --git a/android/test/suitebuilder/SmokeTestSuiteBuilder.java b/android/test/suitebuilder/SmokeTestSuiteBuilder.java
new file mode 100644
index 0000000..01e7ec6
--- /dev/null
+++ b/android/test/suitebuilder/SmokeTestSuiteBuilder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+/**
+ * A suite builder that runs smoke tests.
+ * 
+ * {@hide} Not needed for 1.0 SDK.
+ */
+public class SmokeTestSuiteBuilder extends TestSuiteBuilder {
+
+    public SmokeTestSuiteBuilder(Class clazz) {
+        this(clazz.getName(), clazz.getClassLoader());
+    }
+
+
+    public SmokeTestSuiteBuilder(String name, ClassLoader classLoader) {
+        super(name, classLoader);
+        addRequirements(TestPredicates.SELECT_SMOKE);
+    }
+}
diff --git a/android/test/suitebuilder/TestGrouping.java b/android/test/suitebuilder/TestGrouping.java
new file mode 100644
index 0000000..030bc42
--- /dev/null
+++ b/android/test/suitebuilder/TestGrouping.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import android.test.ClassPathPackageInfoSource;
+import android.util.Log;
+import com.android.internal.util.Predicate;
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Represents a collection of test classes present on the classpath. You can add individual classes
+ * or entire packages. By default sub-packages are included recursively, but methods are
+ * provided to allow for arbitrary inclusion or exclusion of sub-packages. Typically a
+ * {@link TestGrouping} will have only one root package, but this is not a requirement.
+ * 
+ * {@hide} Not needed for 1.0 SDK.
+ */
+class TestGrouping {
+
+    private static final String LOG_TAG = "TestGrouping";
+
+    private final SortedSet<Class<? extends TestCase>> testCaseClasses;
+
+    static final Comparator<Class<? extends TestCase>> SORT_BY_SIMPLE_NAME
+            = new SortBySimpleName();
+
+    static final Comparator<Class<? extends TestCase>> SORT_BY_FULLY_QUALIFIED_NAME
+            = new SortByFullyQualifiedName();
+
+    private final ClassLoader classLoader;
+
+    TestGrouping(Comparator<Class<? extends TestCase>> comparator, ClassLoader classLoader) {
+        testCaseClasses = new TreeSet<Class<? extends TestCase>>(comparator);
+        this.classLoader = classLoader;
+    }
+
+    /**
+     * @return A list of all tests in the package, including small, medium, large,
+     *         flaky, and suppressed tests. Includes sub-packages recursively.
+     */
+    public List<TestMethod> getTests() {
+        List<TestMethod> testMethods = new ArrayList<TestMethod>();
+        for (Class<? extends TestCase> testCase : testCaseClasses) {
+            for (Method testMethod : getTestMethods(testCase)) {
+                testMethods.add(new TestMethod(testMethod, testCase));
+            }
+        }
+        return testMethods;
+    }
+
+    private List<Method> getTestMethods(Class<? extends TestCase> testCaseClass) {
+        List<Method> methods = Arrays.asList(testCaseClass.getMethods());
+        return select(methods, new TestMethodPredicate());
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        TestGrouping other = (TestGrouping) o;
+        if (!this.testCaseClasses.equals(other.testCaseClasses)) {
+            return false;
+        }
+        return this.testCaseClasses.comparator().equals(other.testCaseClasses.comparator());
+    }
+
+    public int hashCode() {
+        return testCaseClasses.hashCode();
+    }
+
+    /**
+     * Include all tests in the given packages and all their sub-packages, unless otherwise
+     * specified. Each of the given packages must contain at least one test class, either directly
+     * or in a sub-package.
+     *
+     * @param packageNames Names of packages to add.
+     */
+    void addPackagesRecursive(String... packageNames) {
+        for (String packageName : packageNames) {
+            List<Class<? extends TestCase>> addedClasses = testCaseClassesInPackage(packageName);
+            if (addedClasses.isEmpty()) {
+                Log.w(LOG_TAG, "Invalid Package: '" + packageName
+                        + "' could not be found or has no tests");
+            }
+            testCaseClasses.addAll(addedClasses);
+        }
+    }
+
+    /**
+     * Exclude all tests in the given packages and all their sub-packages, unless otherwise
+     * specified.
+     *
+     * @param packageNames Names of packages to remove.
+     */
+    void removePackagesRecursive(String... packageNames) {
+        for (String packageName : packageNames) {
+            testCaseClasses.removeAll(testCaseClassesInPackage(packageName));
+        }
+    }
+
+    private List<Class<? extends TestCase>> testCaseClassesInPackage(String packageName) {
+        ClassPathPackageInfoSource source = ClassPathPackageInfoSource.forClassPath(classLoader);
+
+        return selectTestClasses(source.getTopLevelClassesRecursive(packageName));
+    }
+
+    @SuppressWarnings("unchecked")
+    private List<Class<? extends TestCase>> selectTestClasses(Set<Class<?>> allClasses) {
+        List<Class<? extends TestCase>> testClasses = new ArrayList<Class<? extends TestCase>>();
+        for (Class<?> testClass : select(allClasses,
+                new TestCasePredicate())) {
+            testClasses.add((Class<? extends TestCase>) testClass);
+        }
+        return testClasses;
+    }
+
+    private <T> List<T> select(Collection<T> items, Predicate<T> predicate) {
+        ArrayList<T> selectedItems = new ArrayList<T>();
+        for (T item : items) {
+            if (predicate.apply(item)) {
+                selectedItems.add(item);
+            }
+        }
+        return selectedItems;
+    }
+
+    /**
+     * Sort classes by their simple names (i.e. without the package prefix), using
+     * their packages to sort classes with the same name.
+     */
+    private static class SortBySimpleName
+            implements Comparator<Class<? extends TestCase>>, Serializable {
+
+        public int compare(Class<? extends TestCase> class1,
+                Class<? extends TestCase> class2) {
+            int result = class1.getSimpleName().compareTo(class2.getSimpleName());
+            if (result != 0) {
+                return result;
+            }
+            return class1.getName().compareTo(class2.getName());
+        }
+    }
+
+    /**
+     * Sort classes by their fully qualified names (i.e. with the package
+     * prefix).
+     */
+    private static class SortByFullyQualifiedName
+            implements Comparator<Class<? extends TestCase>>, Serializable {
+
+        public int compare(Class<? extends TestCase> class1,
+                Class<? extends TestCase> class2) {
+            return class1.getName().compareTo(class2.getName());
+        }
+    }
+
+    private static class TestCasePredicate implements Predicate<Class<?>> {
+
+        public boolean apply(Class aClass) {
+            int modifiers = ((Class<?>) aClass).getModifiers();
+            return TestCase.class.isAssignableFrom((Class<?>) aClass)
+                    && Modifier.isPublic(modifiers)
+                    && !Modifier.isAbstract(modifiers)
+                    && hasValidConstructor((Class<?>) aClass);
+        }
+
+        @SuppressWarnings("unchecked")
+        private boolean hasValidConstructor(java.lang.Class<?> aClass) {
+            // The cast below is not necessary with the Java 5 compiler, but necessary with the Java 6 compiler,
+            // where the return type of Class.getDeclaredConstructors() was changed
+            // from Constructor<T>[] to Constructor<?>[]
+            Constructor<? extends TestCase>[] constructors
+                    = (Constructor<? extends TestCase>[]) aClass.getConstructors();
+            for (Constructor<? extends TestCase> constructor : constructors) {
+                if (Modifier.isPublic(constructor.getModifiers())) {
+                    java.lang.Class[] parameterTypes = constructor.getParameterTypes();
+                    if (parameterTypes.length == 0 ||
+                            (parameterTypes.length == 1 && parameterTypes[0] == String.class)) {
+                        return true;
+                    }
+                }
+            }
+            Log.i(LOG_TAG, String.format(
+                    "TestCase class %s is missing a public constructor with no parameters " +
+                    "or a single String parameter - skipping",
+                    aClass.getName()));
+            return false;
+        }
+    }
+
+    private static class TestMethodPredicate implements Predicate<Method> {
+
+        public boolean apply(Method method) {
+            return ((method.getParameterTypes().length == 0) &&
+                    (method.getName().startsWith("test")) &&
+                    (method.getReturnType().getSimpleName().equals("void")));
+        }
+    }
+}
diff --git a/android/test/suitebuilder/TestMethod.java b/android/test/suitebuilder/TestMethod.java
new file mode 100644
index 0000000..ae1db5e
--- /dev/null
+++ b/android/test/suitebuilder/TestMethod.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import junit.framework.TestCase;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Represents a test to be run. Can be constructed without instantiating the TestCase or even
+ * loading the class.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class TestMethod {
+
+    private final String enclosingClassname;
+    private final String testMethodName;
+    private final Class<? extends TestCase> enclosingClass;
+
+    public TestMethod(Method method, Class<? extends TestCase> enclosingClass) {
+        this(method.getName(), enclosingClass);
+    }
+
+    public TestMethod(String methodName, Class<? extends TestCase> enclosingClass) {
+        this.enclosingClass = enclosingClass;
+        this.enclosingClassname = enclosingClass.getName();
+        this.testMethodName = methodName;
+    }
+    
+    public TestMethod(TestCase testCase) {
+        this(testCase.getName(), testCase.getClass());
+    }
+
+    public String getName() {
+        return testMethodName;
+    }
+
+    public String getEnclosingClassname() {
+        return enclosingClassname;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        try {
+            return getEnclosingClass().getMethod(getName()).getAnnotation(annotationClass);
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public Class<? extends TestCase> getEnclosingClass() {
+        return enclosingClass;
+    }
+
+    public TestCase createTest()
+            throws InvocationTargetException, IllegalAccessException, InstantiationException {
+        return instantiateTest(enclosingClass, testMethodName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private TestCase instantiateTest(Class testCaseClass, String testName)
+            throws InvocationTargetException, IllegalAccessException, InstantiationException {
+        Constructor[] constructors = testCaseClass.getConstructors();
+
+        if (constructors.length == 0) {
+            return instantiateTest(testCaseClass.getSuperclass(), testName);
+        } else {
+            for (Constructor constructor : constructors) {
+                Class[] params = constructor.getParameterTypes();
+                if (noargsConstructor(params)) {
+                    TestCase test = ((Constructor<? extends TestCase>) constructor).newInstance();
+                    // JUnit will run just the one test if you call
+                    // {@link TestCase#setName(String)}
+                    test.setName(testName);
+                    return test;
+                } else if (singleStringConstructor(params)) {
+                    return ((Constructor<? extends TestCase>) constructor)
+                            .newInstance(testName);
+                }
+            }
+        }
+        throw new RuntimeException("Unable to locate a constructor for "
+                + testCaseClass.getName());
+    }
+
+    private boolean singleStringConstructor(Class[] params) {
+        return (params.length == 1) && (params[0].equals(String.class));
+    }
+
+    private boolean noargsConstructor(Class[] params) {
+        return params.length == 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        TestMethod that = (TestMethod) o;
+
+        if (enclosingClassname != null
+                ? !enclosingClassname.equals(that.enclosingClassname)
+                : that.enclosingClassname != null) {
+            return false;
+        }
+        if (testMethodName != null
+                ? !testMethodName.equals(that.testMethodName)
+                : that.testMethodName != null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result;
+        result = (enclosingClassname != null ? enclosingClassname.hashCode() : 0);
+        result = 31 * result + (testMethodName != null ? testMethodName.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return enclosingClassname + "." + testMethodName;
+    }
+}
diff --git a/android/test/suitebuilder/TestPredicates.java b/android/test/suitebuilder/TestPredicates.java
new file mode 100644
index 0000000..616d1a9
--- /dev/null
+++ b/android/test/suitebuilder/TestPredicates.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.Smoke;
+import android.test.suitebuilder.annotation.Suppress;
+import com.android.internal.util.Predicate;
+import java.lang.annotation.Annotation;
+
+/**
+ * {@hide} Not needed for 1.0 SDK.
+ */
+public class TestPredicates {
+
+    static final Predicate<TestMethod> REJECT_INSTRUMENTATION =
+            not(new AssignableFrom(InstrumentationTestCase.class));
+
+    static final Predicate<TestMethod> SELECT_SMOKE = hasAnnotation(Smoke.class);
+
+    static final Predicate<TestMethod> REJECT_SUPPRESSED = not(hasAnnotation(Suppress.class));
+
+    /**
+     * Return a predicate that checks to see if a {@link TestMethod} has an instance of the supplied
+     * annotation class, either on the method or on the containing class.
+     */
+    public static Predicate<TestMethod> hasAnnotation(Class<? extends Annotation> annotationClass) {
+        return new HasAnnotation(annotationClass);
+    }
+
+    private static class HasAnnotation implements Predicate<TestMethod> {
+
+        private final Class<? extends Annotation> annotationClass;
+
+        private HasAnnotation(Class<? extends Annotation> annotationClass) {
+            this.annotationClass = annotationClass;
+        }
+
+        @Override
+        public boolean apply(TestMethod testMethod) {
+            return testMethod.getAnnotation(annotationClass) != null ||
+                    testMethod.getEnclosingClass().getAnnotation(annotationClass) != null;
+        }
+    }
+
+    /**
+     * Returns a Predicate that evaluates to true iff the given Predicate
+     * evaluates to false.
+     */
+    public static <T> Predicate<T> not(Predicate<? super T> predicate) {
+        return new NotPredicate<T>(predicate);
+    }
+
+    private static class NotPredicate<T> implements Predicate<T> {
+        private final Predicate<? super T> predicate;
+
+        private NotPredicate(Predicate<? super T> predicate) {
+            this.predicate = predicate;
+        }
+
+        public boolean apply(T t) {
+            return !predicate.apply(t);
+        }
+    }
+}
diff --git a/android/test/suitebuilder/TestSuiteBuilder.java b/android/test/suitebuilder/TestSuiteBuilder.java
new file mode 100644
index 0000000..2857696
--- /dev/null
+++ b/android/test/suitebuilder/TestSuiteBuilder.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import android.content.Context;
+import android.test.AndroidTestRunner;
+import android.test.TestCaseUtil;
+import android.util.Log;
+import com.android.internal.util.Predicate;
+import static android.test.suitebuilder.TestGrouping.SORT_BY_FULLY_QUALIFIED_NAME;
+import static android.test.suitebuilder.TestPredicates.REJECT_SUPPRESSED;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Build suites based on a combination of included packages, excluded packages,
+ * and predicates that must be satisfied.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+public class TestSuiteBuilder {
+
+    private final TestGrouping testGrouping;
+    private final Set<Predicate<TestMethod>> predicates = new HashSet<Predicate<TestMethod>>();
+    private List<TestCase> testCases;
+    private TestSuite rootSuite;
+    private TestSuite suiteForCurrentClass;
+    private String currentClassname;
+    private String suiteName;
+
+    /**
+     * The given name is automatically prefixed with the package containing the tests to be run.
+     * If more than one package is specified, the first is used.
+     *
+     * @param clazz Use the class from your .apk. Use the class name for the test suite name.
+     *              Use the class' classloader in order to load classes for testing.
+     *              This is needed when running in the emulator.
+     */
+    public TestSuiteBuilder(Class clazz) {
+        this(clazz.getName(), clazz.getClassLoader());
+    }
+
+    public TestSuiteBuilder(String name, ClassLoader classLoader) {
+        this.suiteName = name;
+        this.testGrouping = new TestGrouping(SORT_BY_FULLY_QUALIFIED_NAME, classLoader);
+        this.testCases = new ArrayList<>();
+        addRequirements(REJECT_SUPPRESSED);
+    }
+
+    /** @hide pending API Council approval */
+    public TestSuiteBuilder addTestClassByName(String testClassName, String testMethodName,
+            Context context) {
+
+        AndroidTestRunner atr = new AndroidTestRunner();
+        atr.setContext(context);
+        atr.setTestClassName(testClassName, testMethodName);
+
+        this.testCases.addAll(atr.getTestCases());
+        return this;
+    }
+
+    /** @hide pending API Council approval */
+    public TestSuiteBuilder addTestSuite(TestSuite testSuite) {
+        for (TestCase testCase : (List<TestCase>) TestCaseUtil.getTests(testSuite, true)) {
+            this.testCases.add(testCase);
+        }
+        return this;
+    }
+
+    /**
+     * Include all tests that satisfy the requirements in the given packages and all sub-packages,
+     * unless otherwise specified.
+     *
+     * @param packageNames Names of packages to add.
+     * @return The builder for method chaining.
+     */
+    public TestSuiteBuilder includePackages(String... packageNames) {
+        testGrouping.addPackagesRecursive(packageNames);
+        return this;
+    }
+
+    /**
+     * Exclude all tests in the given packages and all sub-packages, unless otherwise specified.
+     *
+     * @param packageNames Names of packages to remove.
+     * @return The builder for method chaining.
+     */
+    public TestSuiteBuilder excludePackages(String... packageNames) {
+        testGrouping.removePackagesRecursive(packageNames);
+        return this;
+    }
+
+    /**
+     * Exclude tests that fail to satisfy all of the given predicates.
+     *
+     * @param predicates Predicates to add to the list of requirements.
+     * @return The builder for method chaining.
+     * @hide
+     */
+    public TestSuiteBuilder addRequirements(List<Predicate<TestMethod>> predicates) {
+        this.predicates.addAll(predicates);
+        return this;
+    }
+
+    /**
+     * Include all junit tests that satisfy the requirements in the calling class' package and all
+     * sub-packages.
+     *
+     * @return The builder for method chaining.
+     */
+    public final TestSuiteBuilder includeAllPackagesUnderHere() {
+        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
+
+        String callingClassName = null;
+        String thisClassName = TestSuiteBuilder.class.getName();
+
+        // We want to get the package of this method's calling class. This method's calling class
+        // should be one level below this class in the stack trace.
+        for (int i = 0; i < stackTraceElements.length; i++) {
+            StackTraceElement element = stackTraceElements[i];
+            if (thisClassName.equals(element.getClassName())
+                    && "includeAllPackagesUnderHere".equals(element.getMethodName())) {
+                // We've found this class in the call stack. The calling class must be the
+                // next class in the stack.
+                callingClassName = stackTraceElements[i + 1].getClassName();
+                break;
+            }
+        }
+
+        String packageName = parsePackageNameFromClassName(callingClassName);
+        return includePackages(packageName);
+    }
+
+    /**
+     * Override the default name for the suite being built. This should generally be called if you
+     * call {@code addRequirements(com.android.internal.util.Predicate[])} to make it clear which
+     * tests will be included. The name you specify is automatically prefixed with the package
+     * containing the tests to be run. If more than one package is specified, the first is used.
+     *
+     * @param newSuiteName Prefix of name to give the suite being built.
+     * @return The builder for method chaining.
+     */
+    public TestSuiteBuilder named(String newSuiteName) {
+        suiteName = newSuiteName;
+        return this;
+    }
+
+    /**
+     * Call this method once you've configured your builder as desired.
+     *
+     * @return The suite containing the requested tests.
+     */
+    public final TestSuite build() {
+        rootSuite = new TestSuite(getSuiteName());
+
+        // Keep track of current class so we know when to create a new sub-suite.
+        currentClassname = null;
+        try {
+            for (TestMethod test : testGrouping.getTests()) {
+                if (satisfiesAllPredicates(test)) {
+                    addTest(test);
+                }
+            }
+            if (testCases.size() > 0) {
+                for (TestCase testCase : testCases) {
+                    if (satisfiesAllPredicates(new TestMethod(testCase))) {
+                        addTest(testCase);
+                    }
+                }
+            }
+        } catch (Exception exception) {
+            Log.i("TestSuiteBuilder", "Failed to create test.", exception);
+            TestSuite suite = new TestSuite(getSuiteName());
+            suite.addTest(new FailedToCreateTests(exception));
+            return suite;
+        }
+        return rootSuite;
+    }
+
+    /**
+     * Subclasses use this method to determine the name of the suite.
+     *
+     * @return The package and suite name combined.
+     */
+    protected String getSuiteName() {
+        return suiteName;
+    }
+
+    /**
+     * Exclude tests that fail to satisfy all of the given predicates. If you call this method, you
+     * probably also want to call {@link #named(String)} to override the default suite name.
+     *
+     * @param predicates Predicates to add to the list of requirements.
+     * @return The builder for method chaining.
+     * @hide
+     */
+    public final TestSuiteBuilder addRequirements(Predicate<TestMethod>... predicates) {
+        ArrayList<Predicate<TestMethod>> list = new ArrayList<Predicate<TestMethod>>();
+        Collections.addAll(list, predicates);
+        return addRequirements(list);
+    }
+
+    /**
+     * A special {@link junit.framework.TestCase} used to indicate a failure during the build()
+     * step.
+     *
+     * @deprecated New tests should be written using the
+     * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+     */
+    @Deprecated
+    public static class FailedToCreateTests extends TestCase {
+        private final Exception exception;
+
+        public FailedToCreateTests(Exception exception) {
+            super("testSuiteConstructionFailed");
+            this.exception = exception;
+        }
+
+        public void testSuiteConstructionFailed() {
+            throw new RuntimeException("Exception during suite construction", exception);
+        }
+    }
+
+    private boolean satisfiesAllPredicates(TestMethod test) {
+        for (Predicate<TestMethod> predicate : predicates) {
+            if (!predicate.apply(test)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void addTest(TestMethod testMethod) throws Exception {
+        addSuiteIfNecessary(testMethod.getEnclosingClassname());
+        suiteForCurrentClass.addTest(testMethod.createTest());
+    }
+
+    private void addTest(Test test) {
+        addSuiteIfNecessary(test.getClass().getName());
+        suiteForCurrentClass.addTest(test);
+    }
+
+    private void addSuiteIfNecessary(String parentClassname) {
+        if (!parentClassname.equals(currentClassname)) {
+            currentClassname = parentClassname;
+            suiteForCurrentClass = new TestSuite(parentClassname);
+            rootSuite.addTest(suiteForCurrentClass);
+        }
+    }
+
+    private static String parsePackageNameFromClassName(String className) {
+        return className.substring(0, className.lastIndexOf('.'));
+    }
+}
diff --git a/android/test/suitebuilder/UnitTestSuiteBuilder.java b/android/test/suitebuilder/UnitTestSuiteBuilder.java
new file mode 100644
index 0000000..a746b35
--- /dev/null
+++ b/android/test/suitebuilder/UnitTestSuiteBuilder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+/**
+ * A suite builder that finds unit tests.
+ *
+ * {@hide} Not needed for 1.0 SDK.
+ */
+public class UnitTestSuiteBuilder extends TestSuiteBuilder {
+
+    public UnitTestSuiteBuilder(Class clazz) {
+        this(clazz.getName(), clazz.getClassLoader());
+    }
+
+
+    public UnitTestSuiteBuilder(String name, ClassLoader classLoader) {
+        super(name, classLoader);
+        addRequirements(TestPredicates.REJECT_INSTRUMENTATION);
+    }
+}
diff --git a/android/test/suitebuilder/annotation/LargeTest.java b/android/test/suitebuilder/annotation/LargeTest.java
new file mode 100644
index 0000000..dc77ee6
--- /dev/null
+++ b/android/test/suitebuilder/annotation/LargeTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a test that should run as part of the large tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/LargeTest.html">
+ * LargeTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface LargeTest {
+}
diff --git a/android/test/suitebuilder/annotation/MediumTest.java b/android/test/suitebuilder/annotation/MediumTest.java
new file mode 100644
index 0000000..b941da0
--- /dev/null
+++ b/android/test/suitebuilder/annotation/MediumTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a test that should run as part of the medium tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/MediumTest.html">
+ * MediumTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface MediumTest {
+}
diff --git a/android/test/suitebuilder/annotation/SmallTest.java b/android/test/suitebuilder/annotation/SmallTest.java
new file mode 100644
index 0000000..d3c74f0
--- /dev/null
+++ b/android/test/suitebuilder/annotation/SmallTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a test that should run as part of the small tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/SmallTest.html">
+ * SmallTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SmallTest {
+}
diff --git a/android/test/suitebuilder/annotation/Smoke.java b/android/test/suitebuilder/annotation/Smoke.java
new file mode 100644
index 0000000..3456371
--- /dev/null
+++ b/android/test/suitebuilder/annotation/Smoke.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a test that should run as part of the smoke tests.
+ * The <code>android.test.suitebuilder.SmokeTestSuiteBuilder</code>
+ * will run all tests with this annotation.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface Smoke {
+}
diff --git a/android/test/suitebuilder/annotation/Suppress.java b/android/test/suitebuilder/annotation/Suppress.java
new file mode 100644
index 0000000..629a3cf
--- /dev/null
+++ b/android/test/suitebuilder/annotation/Suppress.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Use this annotation on test classes or test methods that should not be included in a test
+ * suite. If the annotation appears on the class then no tests in that class will be included. If
+ * the annotation appears only on a test method then only that method will be excluded.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/Suppress.html">
+ * Suppress</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface Suppress {
+}