• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.JELLY_BEAN;
4 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
5 import static android.os.Build.VERSION_CODES.LOLLIPOP;
6 import static android.os.Build.VERSION_CODES.M;
7 import static com.google.common.truth.Truth.assertThat;
8 import static org.junit.Assert.assertEquals;
9 import static org.junit.Assert.assertFalse;
10 import static org.junit.Assert.assertNotNull;
11 import static org.junit.Assert.assertNotSame;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertSame;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.robolectric.Robolectric.buildActivity;
17 import static org.robolectric.Robolectric.setupActivity;
18 import static org.robolectric.RuntimeEnvironment.application;
19 import static org.robolectric.Shadows.shadowOf;
20 
21 import android.Manifest;
22 import android.app.ActionBar;
23 import android.app.Activity;
24 import android.app.ActivityOptions;
25 import android.app.Application;
26 import android.app.Dialog;
27 import android.app.Fragment;
28 import android.appwidget.AppWidgetProvider;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.SharedPreferences;
34 import android.content.pm.ActivityInfo;
35 import android.database.Cursor;
36 import android.database.sqlite.SQLiteCursor;
37 import android.media.AudioManager;
38 import android.net.Uri;
39 import android.os.Bundle;
40 import android.view.Display;
41 import android.view.KeyEvent;
42 import android.view.Menu;
43 import android.view.MenuInflater;
44 import android.view.MenuItem;
45 import android.view.View;
46 import android.view.ViewGroup;
47 import android.view.ViewRootImpl;
48 import android.view.Window;
49 import android.widget.FrameLayout;
50 import android.widget.LinearLayout;
51 import android.widget.SearchView;
52 import androidx.test.core.app.ApplicationProvider;
53 import androidx.test.ext.junit.runners.AndroidJUnit4;
54 import java.util.ArrayList;
55 import java.util.List;
56 import java.util.concurrent.atomic.AtomicBoolean;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.robolectric.R;
60 import org.robolectric.Robolectric;
61 import org.robolectric.android.controller.ActivityController;
62 import org.robolectric.annotation.Config;
63 import org.robolectric.shadow.api.Shadow;
64 import org.robolectric.util.TestRunnable;
65 
66 @RunWith(AndroidJUnit4.class)
67 public class ShadowActivityTest {
68   private Activity activity;
69 
70   @Test
shouldUseApplicationLabelFromManifestAsTitleForActivity()71   public void shouldUseApplicationLabelFromManifestAsTitleForActivity() throws Exception {
72     activity = Robolectric.setupActivity(LabelTestActivity1.class);
73     assertThat(activity.getTitle()).isNotNull();
74     assertThat(activity.getTitle().toString()).isEqualTo(activity.getString(R.string.app_name));
75   }
76 
77   @Test
shouldUseActivityLabelFromManifestAsTitleForActivity()78   public void shouldUseActivityLabelFromManifestAsTitleForActivity() throws Exception {
79     activity = Robolectric.setupActivity(LabelTestActivity2.class);
80     assertThat(activity.getTitle()).isNotNull();
81     assertThat(activity.getTitle().toString()).isEqualTo(activity.getString(R.string.activity_name));
82   }
83 
84   @Test
shouldUseActivityLabelFromManifestAsTitleForActivityWithShortName()85   public void shouldUseActivityLabelFromManifestAsTitleForActivityWithShortName() throws Exception {
86     activity = Robolectric.setupActivity(LabelTestActivity3.class);
87     assertThat(activity.getTitle()).isNotNull();
88     assertThat(activity.getTitle().toString()).isEqualTo(activity.getString(R.string.activity_name));
89   }
90 
91   @Test
createActivity_noDisplayFinished_shouldFinishActivity()92   public void createActivity_noDisplayFinished_shouldFinishActivity() {
93     ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
94     controller.get().setTheme(android.R.style.Theme_NoDisplay);
95     controller.create();
96     controller.get().finish();
97     controller.start().visible().resume();
98 
99     activity = controller.get();
100     assertThat(activity.isFinishing()).isTrue();
101   }
102 
103   @Config(minSdk = M)
104   @Test
createActivity_noDisplayNotFinished_shouldThrowIllegalStateException()105   public void createActivity_noDisplayNotFinished_shouldThrowIllegalStateException() {
106     try {
107       ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
108       controller.get().setTheme(android.R.style.Theme_NoDisplay);
109       controller.setup();
110 
111       // For apps targeting above Lollipop MR1, an exception "Activity <activity> did not call
112       // finish() prior to onResume() completing" will be thrown
113       fail("IllegalStateException should be thrown");
114     } catch (IllegalStateException e) {
115       // pass
116     }
117   }
118 
119   public static final class LabelTestActivity1 extends Activity {}
120   public static final class LabelTestActivity2 extends Activity {}
121   public static final class LabelTestActivity3 extends Activity {}
122 
123   @Test
shouldNotComplainIfActivityIsDestroyedWhileAnotherActivityHasRegisteredBroadcastReceivers()124   public void shouldNotComplainIfActivityIsDestroyedWhileAnotherActivityHasRegisteredBroadcastReceivers() throws Exception {
125     ActivityController<DialogCreatingActivity> controller = Robolectric.buildActivity(DialogCreatingActivity.class);
126     activity = controller.get();
127 
128     DialogLifeCycleActivity activity2 = Robolectric.setupActivity(DialogLifeCycleActivity.class);
129     activity2.registerReceiver(new AppWidgetProvider(), new IntentFilter());
130 
131     controller.destroy();
132   }
133 
134   @Test
shouldNotRegisterNullBroadcastReceiver()135   public void shouldNotRegisterNullBroadcastReceiver() {
136     ActivityController<DialogCreatingActivity> controller = Robolectric.buildActivity(DialogCreatingActivity.class);
137     activity = controller.get();
138     activity.registerReceiver(null, new IntentFilter());
139 
140     controller.destroy();
141   }
142 
143   @Test
144   @Config(minSdk = JELLY_BEAN_MR1)
shouldReportDestroyedStatus()145   public void shouldReportDestroyedStatus() {
146     ActivityController<DialogCreatingActivity> controller = Robolectric.buildActivity(DialogCreatingActivity.class);
147     activity = controller.get();
148 
149     controller.destroy();
150     assertThat(activity.isDestroyed()).isTrue();
151   }
152 
153   @Test
startActivity_shouldDelegateToStartActivityForResult()154   public void startActivity_shouldDelegateToStartActivityForResult() {
155 
156     TranscriptActivity activity = Robolectric.setupActivity(TranscriptActivity.class);
157 
158     activity.startActivity(new Intent().setType("image/*"));
159 
160     shadowOf(activity).receiveResult(new Intent().setType("image/*"), Activity.RESULT_OK,
161         new Intent().setData(Uri.parse("content:foo")));
162     assertThat(activity.transcript)
163         .containsExactly(
164             "onActivityResult called with requestCode -1, resultCode -1, intent data content:foo");
165   }
166 
167   public static class TranscriptActivity extends Activity {
168     final List<String> transcript = new ArrayList<>();
169 
170     @Override
onActivityResult(int requestCode, int resultCode, Intent data)171     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
172       transcript.add(
173           "onActivityResult called with requestCode "
174               + requestCode
175               + ", resultCode "
176               + resultCode
177               + ", intent data "
178               + data.getData());
179     }
180   }
181 
182   @Test
startActivities_shouldStartAllActivities()183   public void startActivities_shouldStartAllActivities() {
184     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
185 
186     final Intent view = new Intent(Intent.ACTION_VIEW);
187     final Intent pick = new Intent(Intent.ACTION_PICK);
188     activity.startActivities(new Intent[] {view, pick});
189 
190     assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(pick);
191     assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(view);
192   }
193 
194   @Test
startActivities_withBundle_shouldStartAllActivities()195   public void startActivities_withBundle_shouldStartAllActivities() {
196     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
197 
198     final Intent view = new Intent(Intent.ACTION_VIEW);
199     final Intent pick = new Intent(Intent.ACTION_PICK);
200     activity.startActivities(new Intent[] {view, pick}, new Bundle());
201 
202     assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(pick);
203     assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(view);
204   }
205 
206   @Test
startActivityForResultAndReceiveResult_shouldSendResponsesBackToActivity()207   public void startActivityForResultAndReceiveResult_shouldSendResponsesBackToActivity() throws Exception {
208     TranscriptActivity activity = Robolectric.setupActivity(TranscriptActivity.class);
209     activity.startActivityForResult(new Intent().setType("audio/*"), 123);
210     activity.startActivityForResult(new Intent().setType("image/*"), 456);
211 
212     shadowOf(activity).receiveResult(new Intent().setType("image/*"), Activity.RESULT_OK,
213         new Intent().setData(Uri.parse("content:foo")));
214     assertThat(activity.transcript)
215         .containsExactly(
216             "onActivityResult called with requestCode 456, resultCode -1, intent data content:foo");
217   }
218 
219   @Test
startActivityForResultAndReceiveResult_whenNoIntentMatches_shouldThrowException()220   public void startActivityForResultAndReceiveResult_whenNoIntentMatches_shouldThrowException() throws Exception {
221     ThrowOnResultActivity activity = Robolectric.buildActivity(ThrowOnResultActivity.class).get();
222     activity.startActivityForResult(new Intent().setType("audio/*"), 123);
223     activity.startActivityForResult(new Intent().setType("image/*"), 456);
224 
225     Intent requestIntent = new Intent().setType("video/*");
226     try {
227       shadowOf(activity).receiveResult(requestIntent, Activity.RESULT_OK,
228           new Intent().setData(Uri.parse("content:foo")));
229       fail();
230     } catch (Exception e) {
231       assertThat(e.getMessage()).startsWith("No intent matches " + requestIntent);
232     }
233   }
234 
235   public static class ThrowOnResultActivity extends Activity {
236     @Override
onActivityResult(int requestCode, int resultCode, Intent data)237     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
238       throw new IllegalStateException("should not be called");
239     }
240   }
241 
242   @Test
shouldSupportStartActivityForResult()243   public void shouldSupportStartActivityForResult() throws Exception {
244     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
245     ShadowActivity shadowActivity = shadowOf(activity);
246     Intent intent = new Intent().setClass(activity, DialogLifeCycleActivity.class);
247     assertThat(shadowActivity.getNextStartedActivity()).isNull();
248 
249     activity.startActivityForResult(intent, 142);
250 
251     Intent startedIntent = shadowActivity.getNextStartedActivity();
252     assertThat(startedIntent).isNotNull();
253     assertThat(startedIntent).isSameAs(intent);
254   }
255 
256   @Test
shouldSupportGetStartedActivitiesForResult()257   public void shouldSupportGetStartedActivitiesForResult() throws Exception {
258     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
259     ShadowActivity shadowActivity = shadowOf(activity);
260     Intent intent = new Intent().setClass(activity, DialogLifeCycleActivity.class);
261 
262     activity.startActivityForResult(intent, 142);
263 
264     ShadowActivity.IntentForResult intentForResult = shadowActivity.getNextStartedActivityForResult();
265     assertThat(intentForResult).isNotNull();
266     assertThat(shadowActivity.getNextStartedActivityForResult()).isNull();
267     assertThat(intentForResult.intent).isNotNull();
268     assertThat(intentForResult.intent).isSameAs(intent);
269     assertThat(intentForResult.requestCode).isEqualTo(142);
270   }
271 
272   @Test
shouldSupportPeekStartedActivitiesForResult()273   public void shouldSupportPeekStartedActivitiesForResult() throws Exception {
274     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
275     ShadowActivity shadowActivity = shadowOf(activity);
276     Intent intent = new Intent().setClass(activity, DialogLifeCycleActivity.class);
277 
278     activity.startActivityForResult(intent, 142);
279 
280     ShadowActivity.IntentForResult intentForResult = shadowActivity.peekNextStartedActivityForResult();
281     assertThat(intentForResult).isNotNull();
282     assertThat(shadowActivity.peekNextStartedActivityForResult()).isSameAs(intentForResult);
283     assertThat(intentForResult.intent).isNotNull();
284     assertThat(intentForResult.intent).isSameAs(intent);
285     assertThat(intentForResult.requestCode).isEqualTo(142);
286   }
287 
288   @Test
onContentChangedShouldBeCalledAfterContentViewIsSet()289   public void onContentChangedShouldBeCalledAfterContentViewIsSet() throws RuntimeException {
290     final List<String> transcript = new ArrayList<>();
291     ActivityWithContentChangedTranscript customActivity = Robolectric.setupActivity(ActivityWithContentChangedTranscript.class);
292     customActivity.setTranscript(transcript);
293     customActivity.setContentView(R.layout.main);
294     assertThat(transcript).containsExactly("onContentChanged was called; title is \"Main Layout\"");
295   }
296 
297   @Test
shouldRetrievePackageNameFromTheManifest()298   public void shouldRetrievePackageNameFromTheManifest() throws Exception {
299     assertThat(Robolectric.setupActivity(Activity.class).getPackageName())
300         .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName());
301   }
302 
303   @Test
shouldRunUiTasksImmediatelyByDefault()304   public void shouldRunUiTasksImmediatelyByDefault() throws Exception {
305     TestRunnable runnable = new TestRunnable();
306     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
307     activity.runOnUiThread(runnable);
308     assertTrue(runnable.wasRun);
309   }
310 
311   @Test
shouldQueueUiTasksWhenUiThreadIsPaused()312   public void shouldQueueUiTasksWhenUiThreadIsPaused() throws Exception {
313     ShadowLooper.pauseMainLooper();
314 
315     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
316     TestRunnable runnable = new TestRunnable();
317     activity.runOnUiThread(runnable);
318     assertFalse(runnable.wasRun);
319 
320     ShadowLooper.unPauseMainLooper();
321     assertTrue(runnable.wasRun);
322   }
323 
324   @Test
showDialog_shouldCreatePrepareAndShowDialog()325   public void showDialog_shouldCreatePrepareAndShowDialog() {
326     final DialogLifeCycleActivity activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
327     final AtomicBoolean dialogWasShown = new AtomicBoolean(false);
328 
329     new Dialog(activity) {
330       {
331         activity.dialog = this;
332       }
333 
334       @Override
335       public void show() {
336         dialogWasShown.set(true);
337       }
338     };
339 
340     activity.showDialog(1);
341 
342     assertTrue(activity.createdDialog);
343     assertTrue(activity.preparedDialog);
344     assertTrue(dialogWasShown.get());
345   }
346 
347   @Test
showDialog_shouldCreatePrepareAndShowDialogWithBundle()348   public void showDialog_shouldCreatePrepareAndShowDialogWithBundle() {
349     final DialogLifeCycleActivity activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
350     final AtomicBoolean dialogWasShown = new AtomicBoolean(false);
351 
352     new Dialog(activity) {
353       {
354         activity.dialog = this;
355       }
356 
357       @Override
358       public void show() {
359         dialogWasShown.set(true);
360       }
361     };
362 
363     activity.showDialog(1, new Bundle());
364 
365     assertTrue(activity.createdDialog);
366     assertTrue(activity.preparedDialogWithBundle);
367     assertTrue(dialogWasShown.get());
368   }
369 
370   @Test
showDialog_shouldReturnFalseIfDialogDoesNotExist()371   public void showDialog_shouldReturnFalseIfDialogDoesNotExist() {
372     final DialogLifeCycleActivity activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
373     boolean dialogCreated = activity.showDialog(97, new Bundle());
374 
375     assertThat(dialogCreated).isFalse();
376     assertThat(activity.createdDialog).isTrue();
377     assertThat(activity.preparedDialogWithBundle).isFalse();
378   }
379 
380   @Test
showDialog_shouldReuseDialogs()381   public void showDialog_shouldReuseDialogs() {
382     final DialogCreatingActivity activity = Robolectric.setupActivity(DialogCreatingActivity.class);
383     activity.showDialog(1);
384     Dialog firstDialog = ShadowDialog.getLatestDialog();
385     activity.showDialog(1);
386 
387     Dialog secondDialog = ShadowDialog.getLatestDialog();
388     assertSame("dialogs should be the same instance", firstDialog, secondDialog);
389   }
390 
391   @Test
showDialog_shouldShowDialog()392   public void showDialog_shouldShowDialog() throws Exception {
393     final DialogCreatingActivity activity = Robolectric.setupActivity(DialogCreatingActivity.class);
394     activity.showDialog(1);
395     Dialog dialog = ShadowDialog.getLatestDialog();
396     assertTrue(dialog.isShowing());
397   }
398 
399   @Test
dismissDialog_shouldDismissPreviouslyShownDialog()400   public void dismissDialog_shouldDismissPreviouslyShownDialog() throws Exception {
401     final DialogCreatingActivity activity = Robolectric.setupActivity(DialogCreatingActivity.class);
402     activity.showDialog(1);
403     activity.dismissDialog(1);
404     Dialog dialog = ShadowDialog.getLatestDialog();
405     assertFalse(dialog.isShowing());
406   }
407 
408   @Test(expected = IllegalArgumentException.class)
dismissDialog_shouldThrowExceptionIfDialogWasNotPreviouslyShown()409   public void dismissDialog_shouldThrowExceptionIfDialogWasNotPreviouslyShown() throws Exception {
410     final DialogCreatingActivity activity = Robolectric.setupActivity(DialogCreatingActivity.class);
411     activity.dismissDialog(1);
412   }
413 
414   @Test
removeDialog_shouldCreateDialogAgain()415   public void removeDialog_shouldCreateDialogAgain() {
416     final DialogCreatingActivity activity = Robolectric.setupActivity(DialogCreatingActivity.class);
417     activity.showDialog(1);
418     Dialog firstDialog = ShadowDialog.getLatestDialog();
419 
420     activity.removeDialog(1);
421     assertNull(shadowOf(activity).getDialogById(1));
422 
423     activity.showDialog(1);
424     Dialog secondDialog = ShadowDialog.getLatestDialog();
425 
426     assertNotSame("dialogs should not be the same instance", firstDialog, secondDialog);
427   }
428 
429   @Test
shouldCallOnCreateDialogFromShowDialog()430   public void shouldCallOnCreateDialogFromShowDialog() {
431     ActivityWithOnCreateDialog activity = Robolectric.setupActivity(ActivityWithOnCreateDialog.class);
432     activity.showDialog(123);
433     assertTrue(activity.onCreateDialogWasCalled);
434     assertThat(ShadowDialog.getLatestDialog()).isNotNull();
435   }
436 
437   @Test
shouldCallFinishInOnBackPressed()438   public void shouldCallFinishInOnBackPressed() {
439     Activity activity = new Activity();
440     activity.onBackPressed();
441 
442     assertTrue(activity.isFinishing());
443   }
444 
445   @Test
446   @Config(minSdk = JELLY_BEAN)
shouldCallFinishOnFinishAffinity()447   public void shouldCallFinishOnFinishAffinity() {
448     Activity activity = new Activity();
449     activity.finishAffinity();
450 
451     assertTrue(activity.isFinishing());
452   }
453 
454   @Test
455   @Config(minSdk = LOLLIPOP)
shouldCallFinishOnFinishAndRemoveTask()456   public void shouldCallFinishOnFinishAndRemoveTask() {
457     Activity activity = new Activity();
458     activity.finishAndRemoveTask();
459 
460     assertTrue(activity.isFinishing());
461   }
462 
463   @Test
shouldCallFinishOnFinish()464   public void shouldCallFinishOnFinish() {
465     Activity activity = new Activity();
466     activity.finish();
467 
468     assertTrue(activity.isFinishing());
469   }
470 
471   @Test
shouldSupportCurrentFocus()472   public void shouldSupportCurrentFocus() {
473     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
474     ShadowActivity shadow = shadowOf(activity);
475 
476     assertNull(shadow.getCurrentFocus());
477     View view = new View(activity);
478     shadow.setCurrentFocus(view);
479     assertEquals(view, shadow.getCurrentFocus());
480   }
481 
482   @Test
shouldSetOrientation()483   public void shouldSetOrientation() {
484     activity = Robolectric.setupActivity(DialogLifeCycleActivity.class);
485     activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
486     assertThat(activity.getRequestedOrientation()).isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
487   }
488 
489   @Test
setDefaultKeyMode_shouldSetKeyMode()490   public void setDefaultKeyMode_shouldSetKeyMode() {
491     int[] modes = {
492         Activity.DEFAULT_KEYS_DISABLE,
493         Activity.DEFAULT_KEYS_SHORTCUT,
494         Activity.DEFAULT_KEYS_DIALER,
495         Activity.DEFAULT_KEYS_SEARCH_LOCAL,
496         Activity.DEFAULT_KEYS_SEARCH_GLOBAL
497     };
498     Activity activity = new Activity();
499     ShadowActivity shadow = shadowOf(activity);
500 
501     for (int mode : modes) {
502       activity.setDefaultKeyMode(mode);
503       assertThat(shadow.getDefaultKeymode()).named("Unexpected key mode").isEqualTo(mode);
504     }
505   }
506 
507   @Test // unclear what the correct behavior should be here...
shouldPopulateWindowDecorViewWithMergeLayoutContents()508   public void shouldPopulateWindowDecorViewWithMergeLayoutContents() throws Exception {
509     Activity activity = Robolectric.buildActivity(Activity.class).create().get();
510     activity.setContentView(R.layout.toplevel_merge);
511 
512     View contentView = activity.findViewById(android.R.id.content);
513     assertThat(((ViewGroup) contentView).getChildCount()).isEqualTo(2);
514   }
515 
setContentView_shouldReplaceOldContentView()516   @Test public void setContentView_shouldReplaceOldContentView() throws Exception {
517     View view1 = new View(application);
518     view1.setId(R.id.burritos);
519     View view2 = new View(application);
520     view2.setId(R.id.button);
521 
522     Activity activity = buildActivity(Activity.class).create().get();
523     activity.setContentView(view1);
524     assertSame(view1, activity.findViewById(R.id.burritos));
525 
526     activity.setContentView(view2);
527     assertNull(activity.findViewById(R.id.burritos));
528     assertSame(view2, activity.findViewById(R.id.button));
529   }
530 
531   @Test
onKeyUp_callsOnBackPressedWhichFinishesTheActivity()532   public void onKeyUp_callsOnBackPressedWhichFinishesTheActivity() throws Exception {
533     OnBackPressedActivity activity = buildActivity(OnBackPressedActivity.class).setup().get();
534     boolean downConsumed =
535         activity.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
536     boolean upConsumed =
537         activity.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
538 
539     assertTrue(downConsumed);
540     assertTrue(upConsumed);
541     assertTrue(activity.onBackPressedCalled);
542     assertTrue(activity.isFinishing());
543   }
544 
545   @Test
shouldGiveSharedPreferences()546   public void shouldGiveSharedPreferences() throws Exception {
547     Activity activity = Robolectric.setupActivity(Activity.class);
548     SharedPreferences preferences = activity.getPreferences(Context.MODE_PRIVATE);
549     assertNotNull(preferences);
550     preferences.edit().putString("foo", "bar").commit();
551     assertThat(activity.getPreferences(Context.MODE_PRIVATE).getString("foo", null)).isEqualTo("bar");
552   }
553 
554   @Test
shouldFindContentViewContainerWithChild()555   public void shouldFindContentViewContainerWithChild() throws Exception {
556     Activity activity = buildActivity(Activity.class).create().get();
557     View contentView = new View(activity);
558     activity.setContentView(contentView);
559 
560     FrameLayout contentViewContainer = (FrameLayout) activity.findViewById(android.R.id.content);
561     assertThat(contentViewContainer.getChildAt(0)).isSameAs(contentView);
562   }
563 
564   @Test
shouldFindContentViewContainerWithoutChild()565   public void shouldFindContentViewContainerWithoutChild() throws Exception {
566     Activity activity = buildActivity(Activity.class).create().get();
567 
568     FrameLayout contentViewContainer = (FrameLayout) activity.findViewById(android.R.id.content);
569     assertThat(contentViewContainer.getId()).isEqualTo(android.R.id.content);
570   }
571 
572   @Test
recreateGoesThroughFullLifeCycle()573   public void recreateGoesThroughFullLifeCycle() throws Exception {
574     TestActivity activity = buildActivity(TestActivity.class).get();
575     activity.recreate();
576 
577     assertThat(activity.transcript).containsExactly(
578         "onSaveInstanceState",
579         "onPause",
580         "onStop",
581         "onRetainNonConfigurationInstance",
582         "onDestroy",
583         "onCreate",
584         "onStart",
585         "onRestoreInstanceState",
586         "onResume"
587     );
588 
589     Integer storedValue = (Integer) activity.getLastNonConfigurationInstance();
590     assertEquals(5, storedValue.intValue());
591   }
592 
593   @Test
startAndStopManagingCursorTracksCursors()594   public void startAndStopManagingCursorTracksCursors() throws Exception {
595     TestActivity activity = new TestActivity();
596 
597     ShadowActivity shadow = shadowOf(activity);
598 
599     assertThat(shadow.getManagedCursors()).isNotNull();
600     assertThat(shadow.getManagedCursors().size()).isEqualTo(0);
601 
602     Cursor c = Shadow.newInstanceOf(SQLiteCursor.class);
603     activity.startManagingCursor(c);
604 
605     assertThat(shadow.getManagedCursors()).isNotNull();
606     assertThat(shadow.getManagedCursors().size()).isEqualTo(1);
607     assertThat(shadow.getManagedCursors().get(0)).isSameAs(c);
608 
609     activity.stopManagingCursor(c);
610 
611     assertThat(shadow.getManagedCursors()).isNotNull();
612     assertThat(shadow.getManagedCursors().size()).isEqualTo(0);
613   }
614 
615   @Test
setVolumeControlStream_setsTheSpecifiedStreamType()616   public void setVolumeControlStream_setsTheSpecifiedStreamType() {
617     TestActivity activity = new TestActivity();
618     activity.setVolumeControlStream(AudioManager.STREAM_ALARM);
619     assertThat(activity.getVolumeControlStream()).isEqualTo(AudioManager.STREAM_ALARM);
620   }
621 
622   @Test
decorViewSizeEqualToDisplaySize()623   public void decorViewSizeEqualToDisplaySize() {
624     Activity activity = buildActivity(Activity.class).create().visible().get();
625     View decorView = activity.getWindow().getDecorView();
626     assertThat(decorView).isNotEqualTo(null);
627     ViewRootImpl root = decorView.getViewRootImpl();
628     assertThat(root).isNotEqualTo(null);
629     assertThat(decorView.getWidth()).isNotEqualTo(0);
630     assertThat(decorView.getHeight()).isNotEqualTo(0);
631     Display display = ShadowDisplay.getDefaultDisplay();
632     assertThat(decorView.getWidth()).isEqualTo(display.getWidth());
633     assertThat(decorView.getHeight()).isEqualTo(display.getHeight());
634   }
635 
636   @Test
637   @Config(minSdk = M)
requestsPermissions()638   public void requestsPermissions() {
639     TestActivity activity = new TestActivity();
640     activity.requestPermissions(new String[0], -1);
641   }
642 
643   private static class TestActivity extends Activity {
644     List<String> transcript = new ArrayList<>();
645 
646     private boolean isRecreating = false;
647 
648     @Override
onSaveInstanceState(Bundle outState)649     public void onSaveInstanceState(Bundle outState) {
650       isRecreating = true;
651       transcript.add("onSaveInstanceState");
652       outState.putString("TestActivityKey", "TestActivityValue");
653       super.onSaveInstanceState(outState);
654     }
655 
656     @Override
onRestoreInstanceState(Bundle savedInstanceState)657     public void onRestoreInstanceState(Bundle savedInstanceState) {
658       transcript.add("onRestoreInstanceState");
659       assertTrue(savedInstanceState.containsKey("TestActivityKey"));
660       assertEquals("TestActivityValue", savedInstanceState.getString("TestActivityKey"));
661       super.onRestoreInstanceState(savedInstanceState);
662     }
663 
664     @Override
onRetainNonConfigurationInstance()665     public Object onRetainNonConfigurationInstance() {
666       transcript.add("onRetainNonConfigurationInstance");
667       return 5;
668     }
669 
670     @Override
onPause()671     public void onPause() {
672       transcript.add("onPause");
673       super.onPause();
674     }
675 
676     @Override
onDestroy()677     public void onDestroy() {
678       transcript.add("onDestroy");
679       super.onDestroy();
680     }
681 
682     @Override
onCreate(Bundle savedInstanceState)683     public void onCreate(Bundle savedInstanceState) {
684       transcript.add("onCreate");
685 
686       if (isRecreating) {
687         assertTrue(savedInstanceState.containsKey("TestActivityKey"));
688         assertEquals("TestActivityValue", savedInstanceState.getString("TestActivityKey"));
689       }
690 
691       super.onCreate(savedInstanceState);
692     }
693 
694     @Override
onStart()695     public void onStart() {
696       transcript.add("onStart");
697       super.onStart();
698     }
699 
700     @Override
onPostCreate(Bundle savedInstanceState)701     public void onPostCreate(Bundle savedInstanceState) {
702       transcript.add("onPostCreate");
703       super.onPostCreate(savedInstanceState);
704     }
705 
706     @Override
onStop()707     public void onStop() {
708       transcript.add("onStop");
709       super.onStop();
710     }
711 
712     @Override
onRestart()713     public void onRestart() {
714       transcript.add("onRestart");
715       super.onRestart();
716     }
717 
718     @Override
onResume()719     public void onResume() {
720       transcript.add("onResume");
721       super.onResume();
722     }
723   }
724 
725   @Test
getAndSetParentActivity_shouldWorkForTestingPurposes()726   public void getAndSetParentActivity_shouldWorkForTestingPurposes() throws Exception {
727     Activity parentActivity = new Activity();
728     Activity activity = new Activity();
729     shadowOf(activity).setParent(parentActivity);
730     assertSame(parentActivity, activity.getParent());
731   }
732 
733   @Test
getAndSetRequestedOrientation_shouldRemember()734   public void getAndSetRequestedOrientation_shouldRemember() throws Exception {
735     Activity activity = new Activity();
736     activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
737     assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, activity.getRequestedOrientation());
738   }
739 
740   @Test
getAndSetRequestedOrientation_shouldDelegateToParentIfPresent()741   public void getAndSetRequestedOrientation_shouldDelegateToParentIfPresent() throws Exception {
742     Activity parentActivity = new Activity();
743     Activity activity = new Activity();
744     shadowOf(activity).setParent(parentActivity);
745     parentActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
746     assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, activity.getRequestedOrientation());
747     activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
748     assertEquals(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, parentActivity.getRequestedOrientation());
749   }
750 
751   @Test
shouldSupportIsTaskRoot()752   public void shouldSupportIsTaskRoot() throws Exception {
753     Activity activity = Robolectric.setupActivity(Activity.class);
754     assertTrue(activity.isTaskRoot()); // as implemented, Activities are considered task roots by default
755 
756     shadowOf(activity).setIsTaskRoot(false);
757     assertFalse(activity.isTaskRoot());
758   }
759 
760   @Test
getPendingTransitionEnterAnimationResourceId_should()761   public void getPendingTransitionEnterAnimationResourceId_should() throws Exception {
762     Activity activity = Robolectric.setupActivity(Activity.class);
763     activity.overridePendingTransition(15, 2);
764     assertThat(shadowOf(activity).getPendingTransitionEnterAnimationResourceId()).isEqualTo(15);
765   }
766 
767   @Test
getPendingTransitionExitAnimationResourceId_should()768   public void getPendingTransitionExitAnimationResourceId_should() throws Exception {
769     Activity activity = Robolectric.setupActivity(Activity.class);
770     activity.overridePendingTransition(15, 2);
771     assertThat(shadowOf(activity).getPendingTransitionExitAnimationResourceId()).isEqualTo(2);
772   }
773 
774   @Test
getActionBar_shouldWorkIfActivityHasAnAppropriateTheme()775   public void getActionBar_shouldWorkIfActivityHasAnAppropriateTheme() throws Exception {
776     ActionBarThemedActivity myActivity = Robolectric.buildActivity(ActionBarThemedActivity.class).create().get();
777     ActionBar actionBar = myActivity.getActionBar();
778     assertThat(actionBar).isNotNull();
779   }
780 
781   public static class ActionBarThemedActivity extends Activity {
782 
783     @Override
onCreate(Bundle savedInstanceState)784     protected void onCreate(Bundle savedInstanceState) {
785       super.onCreate(savedInstanceState);
786       setTheme(android.R.style.Theme_Holo_Light);
787       setContentView(new LinearLayout(this));
788     }
789   }
790 
791   @Test
canGetOptionsMenu()792   public void canGetOptionsMenu() throws Exception {
793     Activity activity = buildActivity(OptionsMenuActivity.class).create().visible().get();
794     Menu optionsMenu = shadowOf(activity).getOptionsMenu();
795     assertThat(optionsMenu).isNotNull();
796     assertThat(optionsMenu.getItem(0).getTitle()).isEqualTo("Algebraic!");
797   }
798 
799   @Test
canGetOptionsMenuWithActionMenu()800   public void canGetOptionsMenuWithActionMenu() throws Exception {
801     ActionMenuActivity activity = buildActivity(ActionMenuActivity.class).create().visible().get();
802 
803     SearchView searchView = activity.mSearchView;
804     // This blows up when ShadowPopupMenu existed.
805     searchView.setIconifiedByDefault(false);
806   }
807 
808   @Test
canStartActivityFromFragment()809   public void canStartActivityFromFragment() {
810     final Activity activity = Robolectric.setupActivity(Activity.class);
811 
812     Intent intent = new Intent(Intent.ACTION_VIEW);
813     activity.startActivityFromFragment(new Fragment(), intent, 4);
814 
815     ShadowActivity.IntentForResult intentForResult = shadowOf(activity).getNextStartedActivityForResult();
816     assertThat(intentForResult.intent).isSameAs(intent);
817     assertThat(intentForResult.requestCode).isEqualTo(4);
818   }
819 
820   @Test
canStartActivityFromFragment_withBundle()821   public void canStartActivityFromFragment_withBundle() {
822     final Activity activity = buildActivity(Activity.class).create().get();
823 
824     Bundle options = new Bundle();
825     Intent intent = new Intent(Intent.ACTION_VIEW);
826     activity.startActivityFromFragment(new Fragment(), intent, 5, options);
827 
828     ShadowActivity.IntentForResult intentForResult = shadowOf(activity).getNextStartedActivityForResult();
829     assertThat(intentForResult.intent).isSameAs(intent);
830     assertThat(intentForResult.options).isSameAs(options);
831     assertThat(intentForResult.requestCode).isEqualTo(5);
832   }
833 
834   @Test
shouldUseAnimationOverride()835   public void shouldUseAnimationOverride() {
836     Activity activity = Robolectric.setupActivity(Activity.class);
837     Intent intent = new Intent(activity, OptionsMenuActivity.class);
838 
839     Bundle animationBundle = ActivityOptions.makeCustomAnimation(activity, R.anim.test_anim_1, R.anim.test_anim_1).toBundle();
840     activity.startActivity(intent, animationBundle);
841     assertThat(shadowOf(activity).getNextStartedActivityForResult().options).isSameAs(animationBundle);
842   }
843 
844   @Test
shouldCallActivityLifecycleCallbacks()845   public void shouldCallActivityLifecycleCallbacks() {
846     final List<String> transcript = new ArrayList<>();
847     final ActivityController<Activity> controller = buildActivity(Activity.class);
848     Application applicationContext = ApplicationProvider.getApplicationContext();
849     applicationContext.registerActivityLifecycleCallbacks(
850         new ActivityLifecycleCallbacks(transcript));
851 
852     controller.create();
853     assertThat(transcript).containsExactly("onActivityCreated");
854     transcript.clear();
855 
856     controller.start();
857     assertThat(transcript).containsExactly("onActivityStarted");
858     transcript.clear();
859 
860     controller.resume();
861     assertThat(transcript).containsExactly("onActivityResumed");
862     transcript.clear();
863 
864     controller.saveInstanceState(new Bundle());
865     assertThat(transcript).containsExactly("onActivitySaveInstanceState");
866     transcript.clear();
867 
868     controller.pause();
869     assertThat(transcript).containsExactly("onActivityPaused");
870     transcript.clear();
871 
872     controller.stop();
873     assertThat(transcript).containsExactly("onActivityStopped");
874     transcript.clear();
875 
876     controller.destroy();
877     assertThat(transcript).containsExactly("onActivityDestroyed");
878   }
879 
880   public static class ChildActivity extends Activity { }
881 
882   public static class ParentActivity extends Activity { }
883 
884   @Test
getParentActivityIntent()885   public void getParentActivityIntent() {
886     Activity activity = setupActivity(ChildActivity.class);
887 
888     assertThat(activity.getParentActivityIntent().getComponent().getClassName())
889         .isEqualTo(ParentActivity.class.getName());
890   }
891 
892   @Test
getCallingActivity_defaultsToNull()893   public void getCallingActivity_defaultsToNull() {
894     Activity activity = Robolectric.setupActivity(Activity.class);
895 
896     assertNull(activity.getCallingActivity());
897   }
898 
899   @Test
getCallingActivity_returnsSetValue()900   public void getCallingActivity_returnsSetValue() {
901     Activity activity = Robolectric.setupActivity(Activity.class);
902     ComponentName componentName = new ComponentName("com.example.package", "SomeActivity");
903 
904     ShadowActivity shadowActivity = shadowOf(activity);
905     shadowActivity.setCallingActivity(componentName);
906 
907     assertEquals(componentName, activity.getCallingActivity());
908   }
909 
910   @Test
911   @Config(minSdk = LOLLIPOP)
lockTask()912   public void lockTask() {
913     Activity activity = Robolectric.setupActivity(Activity.class);
914     ShadowActivity shadowActivity = shadowOf(activity);
915 
916     assertThat(shadowActivity.isLockTask()).isFalse();
917 
918     activity.startLockTask();
919     assertThat(shadowActivity.isLockTask()).isTrue();
920 
921     activity.stopLockTask();
922     assertThat(shadowActivity.isLockTask()).isFalse();
923   }
924 
925   @Test
926   @Config(minSdk = M)
getPermission_shouldReturnRequestedPermissions()927   public void getPermission_shouldReturnRequestedPermissions() {
928     // GIVEN
929     String[] permission = {Manifest.permission.CAMERA};
930     int requestCode = 1007;
931     Activity activity = Robolectric.setupActivity(Activity.class);
932 
933     // WHEN
934     activity.requestPermissions(permission, requestCode);
935 
936     // THEN
937     ShadowActivity.PermissionsRequest request = shadowOf(activity).getLastRequestedPermission();
938     assertThat(request.requestCode).isEqualTo(requestCode);
939     assertThat(request.requestedPermissions).isEqualTo(permission);
940   }
941 
942   /////////////////////////////
943 
944   private static class DialogCreatingActivity extends Activity {
945     @Override
onCreateDialog(int id)946     protected Dialog onCreateDialog(int id) {
947       return new Dialog(this);
948     }
949   }
950 
951   private static class OptionsMenuActivity extends Activity {
952 
953     @Override
onCreate(Bundle savedInstanceState)954     protected void onCreate(Bundle savedInstanceState) {
955       super.onCreate(savedInstanceState);
956       // Requesting the action bar causes it to be properly initialized when the Activity becomes visible
957       getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
958       setContentView(new FrameLayout(this));
959     }
960 
961     @Override
onCreateOptionsMenu(Menu menu)962     public boolean onCreateOptionsMenu(Menu menu) {
963       super.onCreateOptionsMenu(menu);
964       menu.add("Algebraic!");
965       return true;
966     }
967   }
968 
969   private static class ActionMenuActivity extends Activity {
970     SearchView mSearchView;
971 
972     @Override
onCreate(Bundle savedInstanceState)973     protected void onCreate(Bundle savedInstanceState) {
974       super.onCreate(savedInstanceState);
975       getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
976       setContentView(new FrameLayout(this));
977     }
978 
979     @Override
onCreateOptionsMenu(Menu menu)980     public boolean onCreateOptionsMenu(Menu menu) {
981       MenuInflater inflater = getMenuInflater();
982       inflater.inflate(R.menu.action_menu, menu);
983 
984       MenuItem searchMenuItem = menu.findItem(R.id.action_search);
985       mSearchView = (SearchView) searchMenuItem.getActionView();
986       return true;
987     }
988   }
989 
990   private static class DialogLifeCycleActivity extends Activity {
991     public boolean createdDialog = false;
992     public boolean preparedDialog = false;
993     public boolean preparedDialogWithBundle = false;
994     public Dialog dialog = null;
995 
996     @Override
onCreate(Bundle savedInstanceState)997     protected void onCreate(Bundle savedInstanceState) {
998       super.onCreate(savedInstanceState);
999       setContentView(new FrameLayout(this));
1000     }
1001 
1002     @Override
onDestroy()1003     protected void onDestroy() {
1004       super.onDestroy();
1005     }
1006 
1007     @Override
onCreateDialog(int id)1008     protected Dialog onCreateDialog(int id) {
1009       createdDialog = true;
1010       return dialog;
1011     }
1012 
1013     @Override
onPrepareDialog(int id, Dialog dialog)1014     protected void onPrepareDialog(int id, Dialog dialog) {
1015       preparedDialog = true;
1016     }
1017 
1018     @Override
onPrepareDialog(int id, Dialog dialog, Bundle bundle)1019     protected void onPrepareDialog(int id, Dialog dialog, Bundle bundle) {
1020       preparedDialogWithBundle = true;
1021     }
1022   }
1023 
1024   private static class ActivityWithOnCreateDialog extends Activity {
1025     boolean onCreateDialogWasCalled = false;
1026 
1027     @Override
onCreateDialog(int id)1028     protected Dialog onCreateDialog(int id) {
1029       onCreateDialogWasCalled = true;
1030       return new Dialog(this);
1031     }
1032   }
1033 
1034   private static class ActivityWithContentChangedTranscript extends Activity {
1035     private List<String> transcript;
1036 
1037     @Override
onContentChanged()1038     public void onContentChanged() {
1039       transcript.add(
1040           "onContentChanged was called; title is \""
1041               + shadowOf((View) findViewById(R.id.title)).innerText()
1042               + "\"");
1043     }
1044 
setTranscript(List<String> transcript)1045     private void setTranscript(List<String> transcript) {
1046       this.transcript = transcript;
1047     }
1048   }
1049 
1050   private static class OnBackPressedActivity extends Activity {
1051     public boolean onBackPressedCalled = false;
1052 
1053     @Override
onBackPressed()1054     public void onBackPressed() {
1055       onBackPressedCalled = true;
1056       super.onBackPressed();
1057     }
1058   }
1059 
1060   private static class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
1061     private final List<String> transcript;
1062 
ActivityLifecycleCallbacks(List<String> transcript)1063     public ActivityLifecycleCallbacks(List<String> transcript) {
1064       this.transcript = transcript;
1065     }
1066 
1067     @Override
onActivityCreated(Activity activity, Bundle bundle)1068     public void onActivityCreated(Activity activity, Bundle bundle) {
1069       transcript.add("onActivityCreated");
1070     }
1071 
1072     @Override
onActivityStarted(Activity activity)1073     public void onActivityStarted(Activity activity) {
1074       transcript.add("onActivityStarted");
1075     }
1076 
1077     @Override
onActivityResumed(Activity activity)1078     public void onActivityResumed(Activity activity) {
1079       transcript.add("onActivityResumed");
1080     }
1081 
1082     @Override
onActivityPaused(Activity activity)1083     public void onActivityPaused(Activity activity) {
1084       transcript.add("onActivityPaused");
1085     }
1086 
1087     @Override
onActivityStopped(Activity activity)1088     public void onActivityStopped(Activity activity) {
1089       transcript.add("onActivityStopped");
1090     }
1091 
1092     @Override
onActivitySaveInstanceState(Activity activity, Bundle bundle)1093     public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
1094       transcript.add("onActivitySaveInstanceState");
1095     }
1096 
1097     @Override
onActivityDestroyed(Activity activity)1098     public void onActivityDestroyed(Activity activity) {
1099       transcript.add("onActivityDestroyed");
1100     }
1101   }
1102 
1103   public static class TestActivityWithAnotherTheme extends ShadowThemeTest.TestActivity {
1104   }
1105 }
1106