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><instrumentation></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 {
+}