• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.integrationtests.axt;
2 
3 import static android.os.Build.VERSION_CODES.P;
4 import static com.google.common.truth.Truth.assertThat;
5 import static org.junit.Assert.assertThrows;
6 
7 import android.app.Activity;
8 import android.app.AppComponentFactory;
9 import android.app.UiAutomation;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.content.res.Configuration;
13 import android.os.Bundle;
14 import android.os.Looper;
15 import androidx.appcompat.R;
16 import androidx.appcompat.app.AppCompatActivity;
17 import androidx.fragment.app.Fragment;
18 import androidx.lifecycle.Lifecycle.State;
19 import androidx.test.core.app.ActivityScenario;
20 import androidx.test.core.app.ApplicationProvider;
21 import androidx.test.ext.junit.runners.AndroidJUnit4;
22 import androidx.test.platform.app.InstrumentationRegistry;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.concurrent.atomic.AtomicReference;
26 import javax.annotation.Nonnull;
27 import javax.annotation.Nullable;
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.robolectric.annotation.Config;
32 
33 /**
34  * Integration tests for {@link ActivityScenario} that verify it behaves consistently on device and
35  * Robolectric.
36  */
37 @RunWith(AndroidJUnit4.class)
38 public class ActivityScenarioTest {
39 
40   private static final List<String> callbacks = new ArrayList<>();
41 
42   /**
43    * @noinspection NewClassNamingConvention
44    */
45   public static class TranscriptActivity extends Activity {
46 
47     @Override
onCreate(Bundle savedInstanceState)48     public void onCreate(Bundle savedInstanceState) {
49       super.onCreate(savedInstanceState);
50       callbacks.add("onCreate");
51     }
52 
53     @Override
onStart()54     public void onStart() {
55       super.onStart();
56       callbacks.add("onStart");
57     }
58 
59     @Override
onPostCreate(Bundle savedInstanceState)60     public void onPostCreate(Bundle savedInstanceState) {
61       super.onPostCreate(savedInstanceState);
62       callbacks.add("onPostCreate");
63     }
64 
65     @Override
onResume()66     public void onResume() {
67       super.onResume();
68       callbacks.add("onResume");
69     }
70 
71     @Override
onPause()72     public void onPause() {
73       super.onPause();
74       callbacks.add("onPause");
75     }
76 
77     @Override
onStop()78     public void onStop() {
79       super.onStop();
80       callbacks.add("onStop " + isChangingConfigurations());
81     }
82 
83     @Override
onRestart()84     public void onRestart() {
85       super.onRestart();
86       callbacks.add("onRestart");
87     }
88 
89     @Override
onDestroy()90     public void onDestroy() {
91       super.onDestroy();
92       callbacks.add("onDestroy");
93     }
94 
95     @Override
onWindowFocusChanged(boolean hasFocus)96     public void onWindowFocusChanged(boolean hasFocus) {
97       super.onWindowFocusChanged(hasFocus);
98       callbacks.add("onWindowFocusChanged " + hasFocus);
99     }
100   }
101 
102   /**
103    * @noinspection NewClassNamingConvention
104    */
105   public static class LifecycleOwnerActivity extends AppCompatActivity {
106     @Override
onCreate(Bundle bundle)107     protected void onCreate(Bundle bundle) {
108       setTheme(R.style.Theme_AppCompat);
109       super.onCreate(bundle);
110     }
111   }
112 
113   @Before
setUp()114   public void setUp() {
115     callbacks.clear();
116   }
117 
118   /**
119    * @noinspection NewClassNamingConvention
120    */
121   public static class ActivityWithCustomConstructor extends Activity {
122     private final int intValue;
123 
ActivityWithCustomConstructor(int intValue)124     public ActivityWithCustomConstructor(int intValue) {
125       this.intValue = intValue;
126     }
127 
getIntValue()128     public int getIntValue() {
129       return intValue;
130     }
131   }
132 
133   /**
134    * @noinspection NewClassNamingConvention
135    */
136   public static class CustomAppComponentFactory extends AppComponentFactory {
137 
138     @Nonnull
139     @Override
instantiateActivity( @onnull ClassLoader cl, @Nonnull String className, @Nullable Intent intent)140     public Activity instantiateActivity(
141         @Nonnull ClassLoader cl, @Nonnull String className, @Nullable Intent intent)
142         throws ClassNotFoundException, IllegalAccessException, InstantiationException {
143       if (className.contains(ActivityWithCustomConstructor.class.getName())) {
144         return new ActivityWithCustomConstructor(100);
145       }
146       return super.instantiateActivity(cl, className, intent);
147     }
148   }
149 
150   @Test
launch_callbackSequence()151   public void launch_callbackSequence() {
152     try (ActivityScenario<TranscriptActivity> activityScenario =
153         ActivityScenario.launch(TranscriptActivity.class)) {
154       assertThat(activityScenario).isNotNull();
155       assertThat(callbacks)
156           .containsExactly(
157               "onCreate", "onStart", "onPostCreate", "onResume", "onWindowFocusChanged true");
158     }
159   }
160 
161   @Test
launch_pauseAndResume_callbackSequence()162   public void launch_pauseAndResume_callbackSequence() {
163     try (ActivityScenario<TranscriptActivity> activityScenario =
164         ActivityScenario.launch(TranscriptActivity.class)) {
165       assertThat(activityScenario).isNotNull();
166       activityScenario.moveToState(State.STARTED);
167       activityScenario.moveToState(State.RESUMED);
168       assertThat(callbacks)
169           .containsExactly(
170               "onCreate",
171               "onStart",
172               "onPostCreate",
173               "onResume",
174               "onWindowFocusChanged true",
175               "onPause",
176               "onResume");
177     }
178   }
179 
180   @Test
launch_stopAndResume_callbackSequence()181   public void launch_stopAndResume_callbackSequence() {
182     try (ActivityScenario<TranscriptActivity> activityScenario =
183         ActivityScenario.launch(TranscriptActivity.class)) {
184       assertThat(activityScenario).isNotNull();
185       activityScenario.moveToState(State.CREATED);
186       activityScenario.moveToState(State.RESUMED);
187       assertThat(callbacks)
188           .containsExactly(
189               "onCreate",
190               "onStart",
191               "onPostCreate",
192               "onResume",
193               "onWindowFocusChanged true",
194               "onPause",
195               "onStop false",
196               "onRestart",
197               "onStart",
198               "onResume");
199     }
200   }
201 
202   @Test
launchAlias_createTargetAndCallbackSequence()203   public void launchAlias_createTargetAndCallbackSequence() {
204     Context context = ApplicationProvider.getApplicationContext();
205     try (ActivityScenario<Activity> activityScenario =
206         ActivityScenario.launch(
207             new Intent()
208                 .setClassName(
209                     context, "org.robolectric.integrationtests.axt.ActivityScenarioTestAlias"))) {
210 
211       assertThat(activityScenario).isNotNull();
212       activityScenario.onActivity(
213           activity -> assertThat(activity).isInstanceOf(TranscriptActivity.class));
214       assertThat(callbacks)
215           .containsExactly(
216               "onCreate", "onStart", "onPostCreate", "onResume", "onWindowFocusChanged true");
217     }
218   }
219 
220   @Test
launch_lifecycleOwnerActivity()221   public void launch_lifecycleOwnerActivity() {
222     try (ActivityScenario<LifecycleOwnerActivity> activityScenario =
223         ActivityScenario.launch(LifecycleOwnerActivity.class)) {
224       assertThat(activityScenario).isNotNull();
225       activityScenario.onActivity(
226           activity ->
227               assertThat(activity.getLifecycle().getCurrentState()).isEqualTo(State.RESUMED));
228       activityScenario.moveToState(State.STARTED);
229       activityScenario.onActivity(
230           activity ->
231               assertThat(activity.getLifecycle().getCurrentState()).isEqualTo(State.STARTED));
232       activityScenario.moveToState(State.CREATED);
233       activityScenario.onActivity(
234           activity ->
235               assertThat(activity.getLifecycle().getCurrentState()).isEqualTo(State.CREATED));
236     }
237   }
238 
239   @Test
recreate_retainFragmentHostingActivity()240   public void recreate_retainFragmentHostingActivity() {
241     Fragment fragment = new Fragment();
242     fragment.setRetainInstance(true);
243     try (ActivityScenario<LifecycleOwnerActivity> activityScenario =
244         ActivityScenario.launch(LifecycleOwnerActivity.class)) {
245       assertThat(activityScenario).isNotNull();
246       activityScenario.onActivity(
247           activity -> {
248             activity
249                 .getSupportFragmentManager()
250                 .beginTransaction()
251                 .add(android.R.id.content, fragment)
252                 .commitNow();
253             assertThat(activity.getSupportFragmentManager().findFragmentById(android.R.id.content))
254                 .isSameInstanceAs(fragment);
255           });
256       activityScenario.recreate();
257       activityScenario.onActivity(
258           activity ->
259               assertThat(
260                       activity.getSupportFragmentManager().findFragmentById(android.R.id.content))
261                   .isSameInstanceAs(fragment));
262     }
263   }
264 
265   @Test
recreate_nonRetainFragmentHostingActivity()266   public void recreate_nonRetainFragmentHostingActivity() {
267     Fragment fragment = new Fragment();
268     fragment.setRetainInstance(false);
269     try (ActivityScenario<LifecycleOwnerActivity> activityScenario =
270         ActivityScenario.launch(LifecycleOwnerActivity.class)) {
271       assertThat(activityScenario).isNotNull();
272       activityScenario.onActivity(
273           activity -> {
274             activity
275                 .getSupportFragmentManager()
276                 .beginTransaction()
277                 .add(android.R.id.content, fragment)
278                 .commitNow();
279             assertThat(activity.getSupportFragmentManager().findFragmentById(android.R.id.content))
280                 .isSameInstanceAs(fragment);
281           });
282       activityScenario.recreate();
283       activityScenario.onActivity(
284           activity ->
285               assertThat(
286                       activity.getSupportFragmentManager().findFragmentById(android.R.id.content))
287                   .isNotSameInstanceAs(fragment));
288     }
289   }
290 
291   @Test
recreate_isChangingConfigurations()292   public void recreate_isChangingConfigurations() {
293     try (ActivityScenario<TranscriptActivity> activityScenario =
294         ActivityScenario.launch(TranscriptActivity.class)) {
295       activityScenario.recreate();
296 
297       assertThat(callbacks).contains("onStop true");
298     }
299   }
300 
301   @Test
setRotation_recreatesActivity()302   public void setRotation_recreatesActivity() {
303     UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
304     try (ActivityScenario<TranscriptActivity> activityScenario =
305         ActivityScenario.launch(TranscriptActivity.class)) {
306       AtomicReference<Activity> originalActivity = new AtomicReference<>();
307       activityScenario.onActivity(originalActivity::set);
308 
309       uiAutomation.setRotation(UiAutomation.ROTATION_FREEZE_90);
310 
311       activityScenario.onActivity(
312           activity -> {
313             assertThat(activity.getResources().getConfiguration().orientation)
314                 .isEqualTo(Configuration.ORIENTATION_LANDSCAPE);
315             assertThat(activity).isNotSameInstanceAs(originalActivity);
316           });
317     }
318   }
319 
320   @Test
onActivityExceptionPropagated()321   public void onActivityExceptionPropagated() {
322     try (ActivityScenario<TranscriptActivity> activityScenario =
323         ActivityScenario.launch(TranscriptActivity.class)) {
324       assertThrows(
325           IllegalStateException.class,
326           () ->
327               activityScenario.onActivity(
328                   activity -> {
329                     throw new IllegalStateException("test");
330                   }));
331     }
332   }
333 
334   @Test
onActivity_runsOnMainLooperThread()335   public void onActivity_runsOnMainLooperThread() {
336     try (ActivityScenario<TranscriptActivity> activityScenario =
337         ActivityScenario.launch(TranscriptActivity.class)) {
338       activityScenario.onActivity(
339           activity ->
340               assertThat(Looper.getMainLooper().getThread()).isEqualTo(Thread.currentThread()));
341     }
342   }
343 
344   @Test
getCallingActivity_empty()345   public void getCallingActivity_empty() {
346     try (ActivityScenario<TranscriptActivity> activityScenario =
347         ActivityScenario.launch(TranscriptActivity.class)) {
348       activityScenario.onActivity(activity -> assertThat(activity.getCallingActivity()).isNull());
349     }
350   }
351 
352   @Test
getCallingActivity_isSet()353   public void getCallingActivity_isSet() {
354     try (ActivityScenario<TranscriptActivity> activityScenario =
355         ActivityScenario.launchActivityForResult(TranscriptActivity.class)) {
356       activityScenario.onActivity(
357           activity ->
358               assertThat(activity.getCallingActivity().getPackageName())
359                   .isEqualTo("org.robolectric.integrationtests.axt"));
360     }
361   }
362 
363   @Test
364   @Config(minSdk = P)
launchActivityWithCustomConstructor()365   public void launchActivityWithCustomConstructor() {
366     try (ActivityScenario<ActivityWithCustomConstructor> activityScenario =
367         ActivityScenario.launch(ActivityWithCustomConstructor.class)) {
368       assertThat(activityScenario.getState()).isEqualTo(State.RESUMED);
369       activityScenario.onActivity(activity -> assertThat(activity.getIntValue()).isEqualTo(100));
370     }
371   }
372 }
373