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