shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java
public ActivityController<T> configurationChange(final Configuration newConfiguration) {
    final Configuration currentConfig = component.getResources().getConfiguration();
    final int changedBits = currentConfig.diff(newConfiguration);
    currentConfig.setTo(newConfiguration);

    // TODO: throw on changedBits == 0 since it non-intuitively calls onConfigurationChanged

    // Can the activity handle itself ALL configuration changes?
    if ((getActivityInfo(component.getApplication()).configChanges & changedBits) == changedBits) {
      shadowMainLooper.runPaused(() -> component.onConfigurationChanged(newConfiguration));

      return this;
    } else {
      @SuppressWarnings("unchecked")
      final T recreatedActivity = (T) ReflectionHelpers.callConstructor(component.getClass());
      final _Activity_ _recreatedActivity_ = reflector(_Activity_.class, recreatedActivity);

      shadowMainLooper.runPaused(
          new Runnable() {
            @Override
            public void run() {
              // Set flags
              ReflectionHelpers.setField(
                  Activity.class, component, "mChangingConfigurations", true);
              ReflectionHelpers.setField(
                  Activity.class, component, "mConfigChangeFlags", changedBits);

              // Perform activity destruction
              final Bundle outState = new Bundle();

              // The order of onPause/onStop/onSaveInstanceState is undefined, but is usually:
              // onPause -> onSaveInstanceState -> onStop
              _component_.performPause();
              _component_.performSaveInstanceState(outState);
              if (RuntimeEnvironment.getApiLevel() <= M) {
                _component_.performStop();
              } else if (RuntimeEnvironment.getApiLevel() <= O_MR1) {
                _component_.performStop(true);
              } else {
                _component_.performStop(true, "configurationChange");
              }

              // This is the true and complete retained state, including loaders and retained
              // fragments.
              final Object nonConfigInstance = _component_.retainNonConfigurationInstances();
              // This is the activity's "user" state
              final Object activityConfigInstance =
                  nonConfigInstance == null
                      ? null // No framework or user state.
                      : reflector(_NonConfigurationInstances_.class, nonConfigInstance)
                          .getActivity();

              _component_.performDestroy();

              // Restore theme in case it was set in the test manually.
              // This is not technically what happens but is purely to make this easier to use in
              // Robolectric.
              ShadowContextThemeWrapper shadowContextThemeWrapper = Shadow.extract(component);
              int theme = shadowContextThemeWrapper.callGetThemeResId();

              // Setup controller for the new activity
              attached = false;
              component = recreatedActivity;
              _component_ = _recreatedActivity_;

              // TODO: Pass nonConfigurationInstance here instead of setting
              // mLastNonConfigurationInstances directly below. This field must be set before
              // attach. Since current implementation sets it after attach(), initialization is not
              // done correctly. For instance, fragment marked as retained is not retained.
              attach(/*lastNonConfigurationInstances=*/ null);

              if (theme != 0) {
                recreatedActivity.setTheme(theme);
              }

              // Set saved non config instance
              _recreatedActivity_.setLastNonConfigurationInstances(nonConfigInstance);
              ShadowActivity shadowActivity = Shadow.extract(recreatedActivity);
              shadowActivity.setLastNonConfigurationInstance(activityConfigInstance);

              // Create lifecycle
              _recreatedActivity_.performCreate(outState);

              if (RuntimeEnvironment.getApiLevel() <= O_MR1) {

                _recreatedActivity_.performStart();

              } else {
                _recreatedActivity_.performStart("configurationChange");
              }

              _recreatedActivity_.performRestoreInstanceState(outState);
              _recreatedActivity_.onPostCreate(outState);
              if (RuntimeEnvironment.getApiLevel() <= O_MR1) {
                _recreatedActivity_.performResume();
              } else {
                _recreatedActivity_.performResume(true, "configurationChange");
              }
              _recreatedActivity_.onPostResume();
              // TODO: Call visible() too.
            }
          });
    }

    return this;
  }
public ActivityController<T> configurationChange(final Configuration newConfiguration) {
    final Configuration currentConfig = component.getResources().getConfiguration();
    final int changedBits = currentConfig.diff(newConfiguration);
    currentConfig.setTo(newConfiguration);

    // TODO: throw on changedBits == 0 since it non-intuitively calls onConfigurationChanged

    // Can the activity handle itself ALL configuration changes?
    if ((getActivityInfo(component.getApplication()).configChanges & changedBits) == changedBits) {
      shadowMainLooper.runPaused(() -> component.onConfigurationChanged(newConfiguration));

      return this;
    } else {
      @SuppressWarnings("unchecked")
      final T recreatedActivity = (T) ReflectionHelpers.callConstructor(component.getClass());
      final _Activity_ _recreatedActivity_ = reflector(_Activity_.class, recreatedActivity);

      shadowMainLooper.runPaused(
          new Runnable() {
            @Override
            public void run() {
              // Set flags
              ReflectionHelpers.setField(
                  Activity.class, component, "mChangingConfigurations", true);
              ReflectionHelpers.setField(
                  Activity.class, component, "mConfigChangeFlags", changedBits);

              // Perform activity destruction
              final Bundle outState = new Bundle();

              // The order of onPause/onStop/onSaveInstanceState is undefined, but is usually:
              // onPause -> onSaveInstanceState -> onStop
              _component_.performPause();
              _component_.performSaveInstanceState(outState);
              if (RuntimeEnvironment.getApiLevel() <= M) {
                _component_.performStop();
              } else if (RuntimeEnvironment.getApiLevel() <= O_MR1) {
                _component_.performStop(true);
              } else {
                _component_.performStop(true, "configurationChange");
              }

              // This is the true and complete retained state, including loaders and retained
              // fragments.
              final Object nonConfigInstance = _component_.retainNonConfigurationInstances();
              // This is the activity's "user" state
              final Object activityConfigInstance =
                  nonConfigInstance == null
                      ? null // No framework or user state.
                      : reflector(_NonConfigurationInstances_.class, nonConfigInstance)
                          .getActivity();

              _component_.performDestroy();

              // Restore theme in case it was set in the test manually.
              // This is not technically what happens but is purely to make this easier to use in
              // Robolectric.
              ShadowContextThemeWrapper shadowContextThemeWrapper = Shadow.extract(component);
              int theme = shadowContextThemeWrapper.callGetThemeResId();

              // Setup controller for the new activity
              attached = false;
              component = recreatedActivity;
              _component_ = _recreatedActivity_;

              // TODO: Pass nonConfigurationInstance here instead of setting
              // mLastNonConfigurationInstances directly below. This field must be set before
              // attach. Since current implementation sets it after attach(), initialization is not
              // done correctly. For instance, fragment marked as retained is not retained.
              attach(/*lastNonConfigurationInstances=*/ null);

              if (theme != 0) {
                recreatedActivity.setTheme(theme);
              }

              // Set saved non config instance
              _recreatedActivity_.setLastNonConfigurationInstances(nonConfigInstance);
              ShadowActivity shadowActivity = Shadow.extract(recreatedActivity);
              shadowActivity.setLastNonConfigurationInstance(activityConfigInstance);

              // Create lifecycle
              _recreatedActivity_.performCreate(outState);

              if (RuntimeEnvironment.getApiLevel() <= O_MR1) {

                _recreatedActivity_.performStart();

              } else {
                _recreatedActivity_.performStart("configurationChange");
              }

              _recreatedActivity_.performRestoreInstanceState(outState);
              _recreatedActivity_.onPostCreate(outState);
              if (RuntimeEnvironment.getApiLevel() <= O_MR1) {
                _recreatedActivity_.performResume();
              } else {
                _recreatedActivity_.performResume(true, "configurationChange");
              }
              _recreatedActivity_.onPostResume();
              // TODO: Call visible() too.
            }
          });
    }

    return this;
  }
public ActivityController < T > configurationChange ( final Configuration newConfiguration ) { final Configuration currentConfig = component . getResources ( ) . getConfiguration ( ) ; final int changedBits = currentConfig . diff ( newConfiguration ) ; currentConfig . setTo ( newConfiguration ) ; // TODO: throw on changedBits == 0 since it non-intuitively calls onConfigurationChanged // Can the activity handle itself ALL configuration changes? if ( ( getActivityInfo ( component . getApplication ( ) ) . configChanges & changedBits ) == changedBits ) { shadowMainLooper . runPaused ( ( ) -> component . onConfigurationChanged ( newConfiguration ) ) ; return this ; } else { @ SuppressWarnings ( "unchecked" ) final T recreatedActivity = ( T ) ReflectionHelpers . callConstructor ( component . getClass ( ) ) ; final _Activity_ _recreatedActivity_ = reflector ( _Activity_ . class , recreatedActivity ) ; shadowMainLooper . runPaused ( new Runnable ( ) { @ Override public void run ( ) { // Set flags ReflectionHelpers . setField ( Activity . class , component , "mChangingConfigurations" , true ) ; ReflectionHelpers . setField ( Activity . class , component , "mConfigChangeFlags" , changedBits ) ; // Perform activity destruction final Bundle outState = new Bundle ( ) ; // The order of onPause/onStop/onSaveInstanceState is undefined, but is usually: // onPause -> onSaveInstanceState -> onStop _component_ . performPause ( ) ; _component_ . performSaveInstanceState ( outState ) ; if ( RuntimeEnvironment . getApiLevel ( ) <= M ) { _component_ . performStop ( ) ; } else if ( RuntimeEnvironment . getApiLevel ( ) <= O_MR1 ) { _component_ . performStop ( true ) ; } else { _component_ . performStop ( true , "configurationChange" ) ; } // This is the true and complete retained state, including loaders and retained // fragments. final Object nonConfigInstance = _component_ . retainNonConfigurationInstances ( ) ; // This is the activity's "user" state final Object activityConfigInstance = nonConfigInstance == null ? null // No framework or user state. : reflector ( _NonConfigurationInstances_ . class , nonConfigInstance ) . getActivity ( ) ; _component_ . performDestroy ( ) ; // Restore theme in case it was set in the test manually. // This is not technically what happens but is purely to make this easier to use in // Robolectric. ShadowContextThemeWrapper shadowContextThemeWrapper = Shadow . extract ( component ) ; int theme = shadowContextThemeWrapper . callGetThemeResId ( ) ; // Setup controller for the new activity attached = false ; component = recreatedActivity ; _component_ = _recreatedActivity_ ; // TODO: Pass nonConfigurationInstance here instead of setting // mLastNonConfigurationInstances directly below. This field must be set before // attach. Since current implementation sets it after attach(), initialization is not // done correctly. For instance, fragment marked as retained is not retained. attach ( /*lastNonConfigurationInstances=*/ null ) ; if ( theme != 0 ) { recreatedActivity . setTheme ( theme ) ; } // Set saved non config instance _recreatedActivity_ . setLastNonConfigurationInstances ( nonConfigInstance ) ; ShadowActivity shadowActivity = Shadow . extract ( recreatedActivity ) ; shadowActivity . setLastNonConfigurationInstance ( activityConfigInstance ) ; // Create lifecycle _recreatedActivity_ . performCreate ( outState ) ; if ( RuntimeEnvironment . getApiLevel ( ) <= O_MR1 ) { _recreatedActivity_ . performStart ( ) ; } else { _recreatedActivity_ . performStart ( "configurationChange" ) ; } _recreatedActivity_ . performRestoreInstanceState ( outState ) ; _recreatedActivity_ . onPostCreate ( outState ) ; if ( RuntimeEnvironment . getApiLevel ( ) <= O_MR1 ) { _recreatedActivity_ . performResume ( ) ; } else { _recreatedActivity_ . performResume ( true , "configurationChange" ) ; } _recreatedActivity_ . onPostResume ( ) ; // TODO: Call visible() too. } } ) ; } return this ; }
Performs a configuration change on the Activity.

If the activity is configured to handle changes without being recreated,
{@link Activity#onConfigurationChanged(Configuration)} will be called. Otherwise, the activity
is recreated as described [here](https://developer.android.com/guide/topics/resources/runtime-changes.html).

@param newConfiguration The new configuration to be set.
@return ActivityController instance
Performs a configuration change on the Activity .