1 package org.robolectric.android.controller; 2 3 import static android.os.Build.VERSION_CODES.O_MR1; 4 import static android.os.Build.VERSION_CODES.P; 5 import static android.os.Build.VERSION_CODES.Q; 6 import static com.google.common.truth.Truth.assertThat; 7 import static com.google.common.truth.Truth.assertWithMessage; 8 import static org.robolectric.Shadows.shadowOf; 9 import static org.robolectric.annotation.LooperMode.Mode.LEGACY; 10 import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; 11 12 import android.app.Activity; 13 import android.app.Fragment; 14 import android.app.WindowConfiguration; 15 import android.content.ComponentName; 16 import android.content.Intent; 17 import android.content.res.Configuration; 18 import android.os.Build.VERSION_CODES; 19 import android.os.Bundle; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.view.ContextThemeWrapper; 23 import android.view.ViewRootImpl; 24 import android.view.Window; 25 import android.view.WindowManager; 26 import android.widget.LinearLayout; 27 import androidx.test.core.app.ApplicationProvider; 28 import androidx.test.ext.junit.runners.AndroidJUnit4; 29 import java.util.ArrayList; 30 import java.util.List; 31 import org.junit.Before; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.robolectric.R; 35 import org.robolectric.Robolectric; 36 import org.robolectric.RuntimeEnvironment; 37 import org.robolectric.annotation.Config; 38 import org.robolectric.annotation.LooperMode; 39 import org.robolectric.shadows.ShadowLooper; 40 import org.robolectric.shadows.ShadowWindowManagerImpl; 41 import org.robolectric.util.Scheduler; 42 import org.robolectric.util.TestRunnable; 43 44 @RunWith(AndroidJUnit4.class) 45 public class ActivityControllerTest { 46 private static final List<String> transcript = new ArrayList<>(); 47 private final ComponentName componentName = 48 new ComponentName("org.robolectric", MyActivity.class.getName()); 49 private final ActivityController<MyActivity> controller = 50 Robolectric.buildActivity(MyActivity.class); 51 52 @Before setUp()53 public void setUp() throws Exception { 54 transcript.clear(); 55 } 56 57 @Test canCreateActivityNotListedInManifest()58 public void canCreateActivityNotListedInManifest() { 59 Activity activity = Robolectric.setupActivity(Activity.class); 60 assertThat(activity).isNotNull(); 61 assertThat(activity.getThemeResId()).isEqualTo(R.style.Theme_Robolectric); 62 } 63 64 public static class TestDelayedPostActivity extends Activity { 65 TestRunnable r1 = new TestRunnable(); 66 TestRunnable r2 = new TestRunnable(); 67 68 @Override onCreate(Bundle savedInstanceState)69 protected void onCreate(Bundle savedInstanceState) { 70 super.onCreate(savedInstanceState); 71 Handler h = new Handler(); 72 h.post(r1); 73 h.postDelayed(r2, 60000); 74 } 75 } 76 77 @Test 78 @LooperMode(LEGACY) pendingTasks_areRunEagerly_whenActivityIsStarted_andSchedulerUnPaused()79 public void pendingTasks_areRunEagerly_whenActivityIsStarted_andSchedulerUnPaused() { 80 final Scheduler s = Robolectric.getForegroundThreadScheduler(); 81 final long startTime = s.getCurrentTime(); 82 TestDelayedPostActivity activity = Robolectric.setupActivity(TestDelayedPostActivity.class); 83 assertWithMessage("immediate task").that(activity.r1.wasRun).isTrue(); 84 assertWithMessage("currentTime").that(s.getCurrentTime()).isEqualTo(startTime); 85 } 86 87 @Test 88 @LooperMode(LEGACY) delayedTasks_areNotRunEagerly_whenActivityIsStarted_andSchedulerUnPaused()89 public void delayedTasks_areNotRunEagerly_whenActivityIsStarted_andSchedulerUnPaused() { 90 // Regression test for issue #1509 91 final Scheduler s = Robolectric.getForegroundThreadScheduler(); 92 final long startTime = s.getCurrentTime(); 93 TestDelayedPostActivity activity = Robolectric.setupActivity(TestDelayedPostActivity.class); 94 assertWithMessage("before flush").that(activity.r2.wasRun).isFalse(); 95 assertWithMessage("currentTime before flush").that(s.getCurrentTime()).isEqualTo(startTime); 96 s.advanceToLastPostedRunnable(); 97 assertWithMessage("after flush").that(activity.r2.wasRun).isTrue(); 98 assertWithMessage("currentTime after flush") 99 .that(s.getCurrentTime()) 100 .isEqualTo(startTime + 60000); 101 } 102 103 @Test shouldSetIntent()104 public void shouldSetIntent() throws Exception { 105 MyActivity myActivity = controller.create().get(); 106 assertThat(myActivity.getIntent()).isNotNull(); 107 assertThat(myActivity.getIntent().getComponent()).isEqualTo(componentName); 108 } 109 110 @Test shouldSetIntentComponentWithCustomIntentWithoutComponentSet()111 public void shouldSetIntentComponentWithCustomIntentWithoutComponentSet() throws Exception { 112 MyActivity myActivity = 113 Robolectric.buildActivity(MyActivity.class, new Intent(Intent.ACTION_VIEW)).create().get(); 114 assertThat(myActivity.getIntent().getAction()).isEqualTo(Intent.ACTION_VIEW); 115 assertThat(myActivity.getIntent().getComponent()).isEqualTo(componentName); 116 } 117 118 @Test shouldSetIntentForGivenActivityInstance()119 public void shouldSetIntentForGivenActivityInstance() throws Exception { 120 ActivityController<MyActivity> activityController = 121 ActivityController.of(new MyActivity()).create(); 122 assertThat(activityController.get().getIntent()).isNotNull(); 123 } 124 125 @Test 126 @LooperMode(LEGACY) whenLooperIsNotPaused_shouldCreateWithMainLooperPaused()127 public void whenLooperIsNotPaused_shouldCreateWithMainLooperPaused() throws Exception { 128 ShadowLooper.unPauseMainLooper(); 129 controller.create(); 130 assertThat(shadowOf(Looper.getMainLooper()).isPaused()).isFalse(); 131 assertThat(transcript).containsAtLeast("finishedOnCreate", "onCreate"); 132 } 133 134 @Test whenLooperIsAlreadyPaused_shouldCreateWithMainLooperPaused()135 public void whenLooperIsAlreadyPaused_shouldCreateWithMainLooperPaused() throws Exception { 136 shadowMainLooper().pause(); 137 controller.create(); 138 assertThat(transcript).contains("finishedOnCreate"); 139 shadowMainLooper().idle(); 140 assertThat(transcript).contains("onCreate"); 141 } 142 143 @Test visible_addsTheDecorViewToTheWindowManager()144 public void visible_addsTheDecorViewToTheWindowManager() { 145 controller.create().visible(); 146 assertThat(controller.get().getWindow().getDecorView().getParent().getClass()) 147 .isEqualTo(ViewRootImpl.class); 148 } 149 150 @Test start_callsPerformStartWhilePaused()151 public void start_callsPerformStartWhilePaused() { 152 controller.create().start(); 153 assertThat(transcript).containsAtLeast("finishedOnStart", "onStart"); 154 } 155 156 @Test stop_callsPerformStopWhilePaused()157 public void stop_callsPerformStopWhilePaused() { 158 controller.create().start().stop(); 159 assertThat(transcript).containsAtLeast("finishedOnStop", "onStop"); 160 } 161 162 @Test restart_callsPerformRestartWhilePaused()163 public void restart_callsPerformRestartWhilePaused() { 164 controller.create().start().stop().restart(); 165 assertThat(transcript).containsAtLeast("finishedOnRestart", "onRestart"); 166 } 167 168 @Test pause_callsPerformPauseWhilePaused()169 public void pause_callsPerformPauseWhilePaused() { 170 controller.create().pause(); 171 assertThat(transcript).containsAtLeast("finishedOnPause", "onPause"); 172 } 173 174 @Test resume_callsPerformResumeWhilePaused()175 public void resume_callsPerformResumeWhilePaused() { 176 controller.create().start().resume(); 177 assertThat(transcript).containsAtLeast("finishedOnResume", "onResume"); 178 } 179 180 @Test destroy_callsPerformDestroyWhilePaused()181 public void destroy_callsPerformDestroyWhilePaused() { 182 controller.create().destroy(); 183 assertThat(transcript).containsAtLeast("finishedOnDestroy", "onDestroy"); 184 } 185 186 @Test destroy_cleansUpWindowManagerState()187 public void destroy_cleansUpWindowManagerState() { 188 WindowManager windowManager = controller.get().getWindowManager(); 189 ShadowWindowManagerImpl shadowWindowManager = 190 ((ShadowWindowManagerImpl) shadowOf(windowManager)); 191 controller.create().start().resume().visible(); 192 assertThat(shadowWindowManager.getViews()) 193 .contains(controller.get().getWindow().getDecorView()); 194 controller.pause().stop().destroy(); 195 assertThat(shadowWindowManager.getViews()) 196 .doesNotContain(controller.get().getWindow().getDecorView()); 197 } 198 199 @Test postCreate_callsOnPostCreateWhilePaused()200 public void postCreate_callsOnPostCreateWhilePaused() { 201 controller.create().postCreate(new Bundle()); 202 assertThat(transcript).containsAtLeast("finishedOnPostCreate", "onPostCreate"); 203 } 204 205 @Test postResume_callsOnPostResumeWhilePaused()206 public void postResume_callsOnPostResumeWhilePaused() { 207 controller.create().postResume(); 208 assertThat(transcript).containsAtLeast("finishedOnPostResume", "onPostResume"); 209 } 210 211 @Test restoreInstanceState_callsPerformRestoreInstanceStateWhilePaused()212 public void restoreInstanceState_callsPerformRestoreInstanceStateWhilePaused() { 213 controller.create().restoreInstanceState(new Bundle()); 214 assertThat(transcript) 215 .containsAtLeast("finishedOnRestoreInstanceState", "onRestoreInstanceState"); 216 } 217 218 @Test newIntent_callsOnNewIntentWhilePaused()219 public void newIntent_callsOnNewIntentWhilePaused() { 220 controller.create().newIntent(new Intent(Intent.ACTION_VIEW)); 221 assertThat(transcript).containsAtLeast("finishedOnNewIntent", "onNewIntent"); 222 } 223 224 @Test userLeaving_callsPerformUserLeavingWhilePaused()225 public void userLeaving_callsPerformUserLeavingWhilePaused() { 226 controller.create().userLeaving(); 227 assertThat(transcript).containsAtLeast("finishedOnUserLeaveHint", "onUserLeaveHint"); 228 } 229 230 @Test setup_callsLifecycleMethodsAndMakesVisible()231 public void setup_callsLifecycleMethodsAndMakesVisible() { 232 controller.setup(); 233 assertThat(transcript) 234 .containsAtLeast("onCreate", "onStart", "onPostCreate", "onResume", "onPostResume"); 235 assertThat(controller.get().getWindow().getDecorView().getParent().getClass()) 236 .isEqualTo(ViewRootImpl.class); 237 } 238 239 @Test setupWithBundle_callsLifecycleMethodsAndMakesVisible()240 public void setupWithBundle_callsLifecycleMethodsAndMakesVisible() { 241 controller.setup(new Bundle()); 242 assertThat(transcript) 243 .containsAtLeast( 244 "onCreate", 245 "onStart", 246 "onRestoreInstanceState", 247 "onPostCreate", 248 "onResume", 249 "onPostResume"); 250 assertThat(controller.get().getWindow().getDecorView().getParent().getClass()) 251 .isEqualTo(ViewRootImpl.class); 252 } 253 254 @Test attach_shouldWork()255 public void attach_shouldWork() { 256 MyActivity activity = Robolectric.buildActivity(MyActivity.class).create().get(); 257 assertThat(activity).isNotNull(); 258 } 259 260 @Test configurationChange_callsLifecycleMethodsAndAppliesConfig()261 public void configurationChange_callsLifecycleMethodsAndAppliesConfig() { 262 Configuration config = 263 new Configuration( 264 ApplicationProvider.getApplicationContext().getResources().getConfiguration()); 265 final float newFontScale = config.fontScale *= 2; 266 267 controller.setup(); 268 transcript.clear(); 269 controller.configurationChange(config); 270 assertThat(transcript) 271 .containsAtLeast( 272 "onPause", 273 "onStop", 274 "onDestroy", 275 "onCreate", 276 "onStart", 277 "onRestoreInstanceState", 278 "onPostCreate", 279 "onResume", 280 "onPostResume"); 281 assertThat(controller.get().getResources().getConfiguration().fontScale) 282 .isEqualTo(newFontScale); 283 } 284 285 @Test configurationChange_callsOnConfigurationChangedAndAppliesConfigWhenAllManaged()286 public void configurationChange_callsOnConfigurationChangedAndAppliesConfigWhenAllManaged() { 287 Configuration config = 288 new Configuration( 289 ApplicationProvider.getApplicationContext().getResources().getConfiguration()); 290 final float newFontScale = config.fontScale *= 2; 291 292 ActivityController<ConfigAwareActivity> configController = 293 Robolectric.buildActivity(ConfigAwareActivity.class).setup(); 294 transcript.clear(); 295 configController.configurationChange(config); 296 assertThat(transcript).containsAtLeast("onConfigurationChanged", "View.onConfigurationChanged"); 297 assertThat(configController.get().getResources().getConfiguration().fontScale) 298 .isEqualTo(newFontScale); 299 } 300 301 @Config(minSdk = P) 302 @Test configurationChange_windowConfigurationChanges_doesNotRecreateActivity()303 public void configurationChange_windowConfigurationChanges_doesNotRecreateActivity() { 304 Configuration config = 305 new Configuration( 306 ApplicationProvider.getApplicationContext().getResources().getConfiguration()); 307 WindowConfiguration windowConfiguration = config.windowConfiguration; 308 windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN); 309 310 ActivityController<ConfigAwareActivity> controller = 311 Robolectric.buildActivity(ConfigAwareActivity.class).setup(); 312 transcript.clear(); 313 controller.configurationChange(config); 314 315 assertThat(transcript).containsAtLeast("onConfigurationChanged", "View.onConfigurationChanged"); 316 assertThat( 317 controller 318 .get() 319 .getResources() 320 .getConfiguration() 321 .windowConfiguration 322 .getWindowingMode()) 323 .isEqualTo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN); 324 } 325 326 @Test 327 @Config(maxSdk = O_MR1) configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged_beforeP()328 public void configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged_beforeP() { 329 configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged( 330 "onSaveInstanceState", "onStop"); 331 } 332 333 @Test 334 @Config(minSdk = P) configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged_fromP()335 public void configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged_fromP() { 336 configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged( 337 "onStop", "onSaveInstanceState"); 338 } 339 340 @Test 341 @Config(qualifiers = "sw600dp") noArgsConfigurationChange_appliesChangedSystemConfiguration()342 public void noArgsConfigurationChange_appliesChangedSystemConfiguration() { 343 ActivityController<ConfigAwareActivity> configController = 344 Robolectric.buildActivity(ConfigAwareActivity.class).setup(); 345 RuntimeEnvironment.setQualifiers("sw800dp"); 346 configController.configurationChange(); 347 assertThat(configController.get().newConfig.smallestScreenWidthDp).isEqualTo(800); 348 } 349 350 @Test 351 @Config(qualifiers = "land") configurationChange_restoresTheme()352 public void configurationChange_restoresTheme() { 353 Configuration config = 354 new Configuration( 355 ApplicationProvider.getApplicationContext().getResources().getConfiguration()); 356 config.orientation = Configuration.ORIENTATION_PORTRAIT; 357 358 controller.get().setTheme(android.R.style.Theme_Black); 359 controller.setup(); 360 transcript.clear(); 361 controller.configurationChange(config); 362 int restoredTheme = shadowOf((ContextThemeWrapper) controller.get()).callGetThemeResId(); 363 assertThat(restoredTheme).isEqualTo(android.R.style.Theme_Black); 364 } 365 366 @Test 367 @Config(qualifiers = "land") configurationChange_reattachesRetainedFragments()368 public void configurationChange_reattachesRetainedFragments() { 369 Configuration config = 370 new Configuration( 371 ApplicationProvider.getApplicationContext().getResources().getConfiguration()); 372 config.orientation = Configuration.ORIENTATION_PORTRAIT; 373 374 ActivityController<NonConfigStateActivity> configController = 375 Robolectric.buildActivity(NonConfigStateActivity.class).setup(); 376 NonConfigStateActivity activity = configController.get(); 377 Fragment retainedFragment = activity.retainedFragment; 378 Fragment otherFragment = activity.nonRetainedFragment; 379 configController.configurationChange(config); 380 activity = configController.get(); 381 382 assertThat(activity.retainedFragment).isNotNull(); 383 assertThat(activity.retainedFragment).isSameInstanceAs(retainedFragment); 384 assertThat(activity.nonRetainedFragment).isNotNull(); 385 assertThat(activity.nonRetainedFragment).isNotSameInstanceAs(otherFragment); 386 } 387 388 @Test isChangingConfiguration()389 public void isChangingConfiguration() { 390 try (ActivityController<ConfigChangeActivity> controller = 391 Robolectric.buildActivity(ConfigChangeActivity.class)) { 392 393 controller.recreate(); 394 395 assertThat(transcript).containsExactly("onPause true", "onStop true", "onDestroy true"); 396 } 397 } 398 399 private static class ConfigChangeActivity extends Activity { 400 401 @Override onPause()402 public void onPause() { 403 super.onPause(); 404 transcript.add("onPause " + isChangingConfigurations()); 405 } 406 407 @Override onStop()408 public void onStop() { 409 super.onStop(); 410 transcript.add("onStop " + isChangingConfigurations()); 411 } 412 413 @Override onDestroy()414 public void onDestroy() { 415 super.onDestroy(); 416 transcript.add("onDestroy " + isChangingConfigurations()); 417 } 418 } 419 420 @Test windowFocusChanged()421 public void windowFocusChanged() { 422 controller.setup(); 423 assertThat(transcript).doesNotContain("finishedOnWindowFocusChanged"); 424 assertThat(controller.get().hasWindowFocus()).isFalse(); 425 426 transcript.clear(); 427 428 controller.windowFocusChanged(true); 429 assertThat(transcript).containsExactly("finishedOnWindowFocusChanged"); 430 assertThat(controller.get().hasWindowFocus()).isTrue(); 431 } 432 433 @Test 434 @Config(minSdk = VERSION_CODES.Q) onTopActivityResumedCalledWithSetup()435 public void onTopActivityResumedCalledWithSetup() { 436 controller.setup(); 437 assertThat(transcript).contains("finishedOnTopResumedActivityChanged"); 438 } 439 440 @Test 441 @Config(maxSdk = VERSION_CODES.P) onTopActivityResumedNotCalledWithSetupPreQ()442 public void onTopActivityResumedNotCalledWithSetupPreQ() { 443 controller.setup(); 444 assertThat(transcript).doesNotContain("finishedOnTopResumedActivityChanged"); 445 } 446 447 @Test close_transitionsActivityStateToDestroyed()448 public void close_transitionsActivityStateToDestroyed() { 449 Robolectric.buildActivity(MyActivity.class).close(); 450 assertThat(transcript).isEmpty(); 451 transcript.clear(); 452 453 Robolectric.buildActivity(MyActivity.class).create().close(); 454 assertThat(transcript) 455 .containsExactly("onCreate", "finishedOnCreate", "onDestroy", "finishedOnDestroy"); 456 transcript.clear(); 457 458 Robolectric.buildActivity(MyActivity.class).create().start().close(); 459 assertThat(transcript) 460 .containsExactly( 461 "onCreate", 462 "finishedOnCreate", 463 "onStart", 464 "finishedOnStart", 465 "onStop", 466 "finishedOnStop", 467 "onDestroy", 468 "finishedOnDestroy"); 469 transcript.clear(); 470 471 Robolectric.buildActivity(MyActivity.class).setup().close(); 472 List<String> expectedStringList = new ArrayList<>(); 473 expectedStringList.add("onCreate"); 474 expectedStringList.add("finishedOnCreate"); 475 expectedStringList.add("onStart"); 476 expectedStringList.add("finishedOnStart"); 477 expectedStringList.add("onPostCreate"); 478 expectedStringList.add("finishedOnPostCreate"); 479 expectedStringList.add("onResume"); 480 expectedStringList.add("finishedOnResume"); 481 expectedStringList.add("onPostResume"); 482 expectedStringList.add("finishedOnPostResume"); 483 if (RuntimeEnvironment.getApiLevel() >= Q) { 484 expectedStringList.add("finishedOnTopResumedActivityChanged"); 485 } 486 expectedStringList.add("onPause"); 487 expectedStringList.add("finishedOnPause"); 488 expectedStringList.add("onStop"); 489 expectedStringList.add("finishedOnStop"); 490 expectedStringList.add("onDestroy"); 491 expectedStringList.add("finishedOnDestroy"); 492 assertThat(transcript).containsExactly(expectedStringList.toArray()); 493 } 494 495 @Test close_tryWithResources_getsDestroyed()496 public void close_tryWithResources_getsDestroyed() { 497 try (ActivityController<MyActivity> ignored = 498 Robolectric.buildActivity(MyActivity.class).setup()) { 499 // no-op 500 } 501 List<String> expectedStringList = new ArrayList<>(); 502 expectedStringList.add("onCreate"); 503 expectedStringList.add("finishedOnCreate"); 504 expectedStringList.add("onStart"); 505 expectedStringList.add("finishedOnStart"); 506 expectedStringList.add("onPostCreate"); 507 expectedStringList.add("finishedOnPostCreate"); 508 expectedStringList.add("onResume"); 509 expectedStringList.add("finishedOnResume"); 510 expectedStringList.add("onPostResume"); 511 expectedStringList.add("finishedOnPostResume"); 512 if (RuntimeEnvironment.getApiLevel() >= Q) { 513 expectedStringList.add("finishedOnTopResumedActivityChanged"); 514 } 515 expectedStringList.add("onPause"); 516 expectedStringList.add("finishedOnPause"); 517 expectedStringList.add("onStop"); 518 expectedStringList.add("finishedOnStop"); 519 expectedStringList.add("onDestroy"); 520 expectedStringList.add("finishedOnDestroy"); 521 assertThat(transcript).containsExactly(expectedStringList.toArray()); 522 } 523 configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged( String secondExpected, String thirdExpected)524 private void configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged( 525 String secondExpected, String thirdExpected) { 526 Configuration config = 527 new Configuration( 528 ApplicationProvider.getApplicationContext().getResources().getConfiguration()); 529 final float newFontScale = config.fontScale *= 2; 530 final int newOrientation = config.orientation = (config.orientation + 1) % 3; 531 532 ActivityController<ConfigAwareActivity> configController = 533 Robolectric.buildActivity(ConfigAwareActivity.class).setup(); 534 transcript.clear(); 535 configController.configurationChange(config); 536 assertThat(transcript) 537 .containsAtLeast( 538 "onPause", 539 secondExpected, 540 thirdExpected, 541 "onDestroy", 542 "onCreate", 543 "onStart", 544 "onResume") 545 .inOrder(); 546 assertThat(configController.get().getResources().getConfiguration().fontScale) 547 .isEqualTo(newFontScale); 548 assertThat(configController.get().getResources().getConfiguration().orientation) 549 .isEqualTo(newOrientation); 550 } 551 552 public static class MyActivity extends Activity { 553 @Override onRestoreInstanceState(Bundle savedInstanceState)554 protected void onRestoreInstanceState(Bundle savedInstanceState) { 555 super.onRestoreInstanceState(savedInstanceState); 556 transcribeWhilePaused("onRestoreInstanceState"); 557 transcript.add("finishedOnRestoreInstanceState"); 558 } 559 560 @Override onSaveInstanceState(Bundle outState)561 protected void onSaveInstanceState(Bundle outState) { 562 super.onSaveInstanceState(outState); 563 transcribeWhilePaused("onSaveInstanceState"); 564 transcript.add("finishedOnSaveInstanceState"); 565 } 566 567 @Override onCreate(Bundle savedInstanceState)568 protected void onCreate(Bundle savedInstanceState) { 569 super.onCreate(savedInstanceState); 570 getWindow().requestFeature(Window.FEATURE_ACTION_BAR); 571 setContentView( 572 new LinearLayout(this) { 573 @Override 574 protected void onConfigurationChanged(Configuration configuration) { 575 super.onConfigurationChanged(configuration); 576 transcribeWhilePaused("View.onConfigurationChanged"); 577 } 578 }); 579 transcribeWhilePaused("onCreate"); 580 transcript.add("finishedOnCreate"); 581 } 582 583 @Override onPostCreate(Bundle savedInstanceState)584 protected void onPostCreate(Bundle savedInstanceState) { 585 super.onPostCreate(savedInstanceState); 586 transcribeWhilePaused("onPostCreate"); 587 transcript.add("finishedOnPostCreate"); 588 } 589 590 @Override onPostResume()591 protected void onPostResume() { 592 super.onPostResume(); 593 transcribeWhilePaused("onPostResume"); 594 transcript.add("finishedOnPostResume"); 595 } 596 597 @Override onDestroy()598 protected void onDestroy() { 599 super.onDestroy(); 600 transcribeWhilePaused("onDestroy"); 601 transcript.add("finishedOnDestroy"); 602 } 603 604 @Override onStart()605 protected void onStart() { 606 super.onStart(); 607 transcribeWhilePaused("onStart"); 608 transcript.add("finishedOnStart"); 609 } 610 611 @Override onStop()612 protected void onStop() { 613 super.onStop(); 614 transcribeWhilePaused("onStop"); 615 transcript.add("finishedOnStop"); 616 } 617 618 @Override onResume()619 protected void onResume() { 620 super.onResume(); 621 transcribeWhilePaused("onResume"); 622 transcript.add("finishedOnResume"); 623 } 624 625 @Override onRestart()626 protected void onRestart() { 627 super.onRestart(); 628 transcribeWhilePaused("onRestart"); 629 transcript.add("finishedOnRestart"); 630 } 631 632 @Override onPause()633 protected void onPause() { 634 super.onPause(); 635 transcribeWhilePaused("onPause"); 636 transcript.add("finishedOnPause"); 637 } 638 639 @Override onNewIntent(Intent intent)640 protected void onNewIntent(Intent intent) { 641 super.onNewIntent(intent); 642 transcribeWhilePaused("onNewIntent"); 643 transcript.add("finishedOnNewIntent"); 644 } 645 646 @Override onUserLeaveHint()647 protected void onUserLeaveHint() { 648 super.onUserLeaveHint(); 649 transcribeWhilePaused("onUserLeaveHint"); 650 transcript.add("finishedOnUserLeaveHint"); 651 } 652 653 @Override onConfigurationChanged(Configuration newConfig)654 public void onConfigurationChanged(Configuration newConfig) { 655 super.onConfigurationChanged(newConfig); 656 transcribeWhilePaused("onConfigurationChanged"); 657 transcript.add("finishedOnConfigurationChanged"); 658 } 659 660 @Override onWindowFocusChanged(boolean newFocus)661 public void onWindowFocusChanged(boolean newFocus) { 662 super.onWindowFocusChanged(newFocus); 663 transcript.add("finishedOnWindowFocusChanged"); 664 } 665 666 @Override onTopResumedActivityChanged(boolean isTopResumedActivity)667 public void onTopResumedActivityChanged(boolean isTopResumedActivity) { 668 super.onTopResumedActivityChanged(isTopResumedActivity); 669 transcript.add("finishedOnTopResumedActivityChanged"); 670 } 671 transcribeWhilePaused(final String event)672 private void transcribeWhilePaused(final String event) { 673 runOnUiThread(() -> transcript.add(event)); 674 } 675 } 676 677 public static class ConfigAwareActivity extends MyActivity { 678 679 Configuration newConfig; 680 681 @Override onCreate(Bundle savedInstanceState)682 protected void onCreate(Bundle savedInstanceState) { 683 super.onCreate(savedInstanceState); 684 if (savedInstanceState != null) { 685 assertThat(savedInstanceState.getSerializable("test")).isNotNull(); 686 } 687 } 688 689 @Override onSaveInstanceState(Bundle outState)690 public void onSaveInstanceState(Bundle outState) { 691 super.onSaveInstanceState(outState); 692 outState.putSerializable("test", new Exception()); 693 } 694 695 @Override onConfigurationChanged(Configuration newConfig)696 public void onConfigurationChanged(Configuration newConfig) { 697 this.newConfig = new Configuration(newConfig); 698 super.onConfigurationChanged(newConfig); 699 } 700 } 701 702 public static final class NonConfigStateActivity extends Activity { 703 Fragment retainedFragment; 704 Fragment nonRetainedFragment; 705 706 @Override onCreate(Bundle savedInstanceState)707 protected void onCreate(Bundle savedInstanceState) { 708 super.onCreate(savedInstanceState); 709 if (savedInstanceState == null) { 710 retainedFragment = new Fragment(); 711 retainedFragment.setRetainInstance(true); 712 nonRetainedFragment = new Fragment(); 713 getFragmentManager() 714 .beginTransaction() 715 .add(android.R.id.content, retainedFragment, "retained") 716 .add(android.R.id.content, nonRetainedFragment, "non-retained") 717 .commit(); 718 } else { 719 retainedFragment = getFragmentManager().findFragmentByTag("retained"); 720 nonRetainedFragment = getFragmentManager().findFragmentByTag("non-retained"); 721 } 722 } 723 } 724 } 725