1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.test; 18 19 import android.app.Activity; 20 import android.content.Intent; 21 22 import java.lang.reflect.Method; 23 24 /** 25 * This class provides functional testing of a single activity. The activity under test will 26 * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity()) 27 * and you will then be able to manipulate your Activity directly. 28 * 29 * <p>Other options supported by this test case include: 30 * <ul> 31 * <li>You can run any test method on the UI thread (see {@link android.test.UiThreadTest}).</li> 32 * <li>You can inject custom Intents into your Activity (see 33 * {@link #setActivityIntent(Intent)}).</li> 34 * </ul> 35 * 36 * <p>This class replaces {@link android.test.ActivityInstrumentationTestCase}, which is deprecated. 37 * New tests should be written using this base class. 38 * 39 * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}. 40 */ 41 public abstract class ActivityInstrumentationTestCase2<T extends Activity> 42 extends ActivityTestCase { 43 Class<T> mActivityClass; 44 boolean mInitialTouchMode = false; 45 Intent mActivityIntent = null; 46 47 /** 48 * Creates an {@link ActivityInstrumentationTestCase2}. 49 * 50 * @param pkg ignored - no longer in use. 51 * @param activityClass The activity to test. This must be a class in the instrumentation 52 * targetPackage specified in the AndroidManifest.xml 53 * 54 * @deprecated use {@link #ActivityInstrumentationTestCase2(Class)} instead 55 */ 56 @Deprecated ActivityInstrumentationTestCase2(String pkg, Class<T> activityClass)57 public ActivityInstrumentationTestCase2(String pkg, Class<T> activityClass) { 58 this(activityClass); 59 } 60 61 /** 62 * Creates an {@link ActivityInstrumentationTestCase2}. 63 * 64 * @param activityClass The activity to test. This must be a class in the instrumentation 65 * targetPackage specified in the AndroidManifest.xml 66 */ ActivityInstrumentationTestCase2(Class<T> activityClass)67 public ActivityInstrumentationTestCase2(Class<T> activityClass) { 68 mActivityClass = activityClass; 69 } 70 71 /** 72 * Get the Activity under test, starting it if necessary. 73 * 74 * For each test method invocation, the Activity will not actually be created until the first 75 * time this method is called. 76 * 77 * <p>If you wish to provide custom setup values to your Activity, you may call 78 * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)} 79 * before your first call to getActivity(). Calling them after your Activity has 80 * started will have no effect. 81 * 82 * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread. 83 * If your test method is annotated with {@link android.test.UiThreadTest}, then your Activity 84 * will be started automatically just before your test method is run. You still call this 85 * method in order to get the Activity under test. 86 * 87 * @return the Activity under test 88 */ 89 @Override getActivity()90 public T getActivity() { 91 Activity a = super.getActivity(); 92 if (a == null) { 93 // set initial touch mode 94 getInstrumentation().setInTouchMode(mInitialTouchMode); 95 final String targetPackage = getInstrumentation().getTargetContext().getPackageName(); 96 // inject custom intent, if provided 97 if (mActivityIntent == null) { 98 a = launchActivity(targetPackage, mActivityClass, null); 99 } else { 100 a = launchActivityWithIntent(targetPackage, mActivityClass, mActivityIntent); 101 } 102 setActivity(a); 103 } 104 return (T) a; 105 } 106 107 /** 108 * Call this method before the first call to {@link #getActivity} to inject a customized Intent 109 * into the Activity under test. 110 * 111 * <p>If you do not call this, the default intent will be provided. If you call this after 112 * your Activity has been started, it will have no effect. 113 * 114 * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread. 115 * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call 116 * {@link #setActivityIntent(Intent)} from {@link #setUp()}. 117 * 118 * <p>The default Intent (if this method is not called) is: 119 * action = {@link Intent#ACTION_MAIN} 120 * flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK} 121 * All other fields are null or empty. 122 * 123 * @param i The Intent to start the Activity with, or null to reset to the default Intent. 124 */ setActivityIntent(Intent i)125 public void setActivityIntent(Intent i) { 126 mActivityIntent = i; 127 } 128 129 /** 130 * Call this method before the first call to {@link #getActivity} to set the initial touch 131 * mode for the Activity under test. 132 * 133 * <p>If you do not call this, the touch mode will be false. If you call this after 134 * your Activity has been started, it will have no effect. 135 * 136 * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread. 137 * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call 138 * {@link #setActivityInitialTouchMode(boolean)} from {@link #setUp()}. 139 * 140 * @param initialTouchMode true if the Activity should be placed into "touch mode" when started 141 */ setActivityInitialTouchMode(boolean initialTouchMode)142 public void setActivityInitialTouchMode(boolean initialTouchMode) { 143 mInitialTouchMode = initialTouchMode; 144 } 145 146 @Override setUp()147 protected void setUp() throws Exception { 148 super.setUp(); 149 150 boolean mInitialTouchMode = false; 151 Intent mActivityIntent = null; 152 } 153 154 @Override tearDown()155 protected void tearDown() throws Exception { 156 // Finish the Activity off (unless was never launched anyway) 157 Activity a = super.getActivity(); 158 if (a != null) { 159 a.finish(); 160 setActivity(null); 161 } 162 163 // Scrub out members - protects against memory leaks in the case where someone 164 // creates a non-static inner class (thus referencing the test case) and gives it to 165 // someone else to hold onto 166 scrubClass(ActivityInstrumentationTestCase2.class); 167 168 super.tearDown(); 169 } 170 171 /** 172 * Runs the current unit test. If the unit test is annotated with 173 * {@link android.test.UiThreadTest}, force the Activity to be created before switching to 174 * the UI thread. 175 */ 176 @Override runTest()177 protected void runTest() throws Throwable { 178 try { 179 Method method = getClass().getMethod(getName(), (Class[]) null); 180 if (method.isAnnotationPresent(UiThreadTest.class)) { 181 getActivity(); 182 } 183 } catch (Exception e) { 184 // eat the exception here; super.runTest() will catch it again and handle it properly 185 } 186 super.runTest(); 187 } 188 189 } 190