• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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