Search in sources :

Example 1 with ShadowContextThemeWrapper

use of org.robolectric.shadows.ShadowContextThemeWrapper in project robolectric by robolectric.

the class ActivityController method configurationChange.

/**
 * Performs a configuration change on the Activity.
 *
 * <p>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 <a
 * href="https://developer.android.com/guide/topics/resources/runtime-changes.html">here</a>.
 *
 * @param newConfiguration The new configuration to be set.
 * @return ActivityController instance
 */
public ActivityController<T> configurationChange(final Configuration newConfiguration) {
    final Configuration currentConfig = component.getResources().getConfiguration();
    final int changedBits = currentConfig.diff(newConfiguration);
    currentConfig.setTo(newConfiguration);
    // Can the activity handle itself ALL configuration changes?
    if ((getActivityInfo(component.getApplication()).configChanges & changedBits) == changedBits) {
        shadowMainLooper.runPaused(() -> {
            component.onConfigurationChanged(newConfiguration);
            ViewRootImpl root = getViewRoot();
            if (root != null) {
                if (RuntimeEnvironment.getApiLevel() <= N_MR1) {
                    ReflectionHelpers.callInstanceMethod(root, "updateConfiguration", ClassParameter.from(Configuration.class, newConfiguration), ClassParameter.from(boolean.class, false));
                } else {
                    root.updateConfiguration(Display.INVALID_DISPLAY);
                }
            }
        });
        return this;
    } else {
        @SuppressWarnings("unchecked") final T recreatedActivity = (T) ReflectionHelpers.callConstructor(component.getClass());
        final _Activity_ _recreatedActivity_ = reflector(_Activity_.class, recreatedActivity);
        shadowMainLooper.runPaused(() -> {
            // Set flags
            _component_.setChangingConfigurations(true);
            _component_.setConfigChangeFlags(changedBits);
            // Perform activity destruction
            final Bundle outState = new Bundle();
            // The order of onPause/onStop/onSaveInstanceState is undefined, but is usually:
            // onPause -> onSaveInstanceState -> onStop before API P, and onPause -> onStop ->
            // onSaveInstanceState from API P.
            // See
            // https://developer.android.com/reference/android/app/Activity#onSaveInstanceState(android.os.Bundle) for documentation explained.
            // And see ActivityThread#callActivityOnStop for related code.
            _component_.performPause();
            if (RuntimeEnvironment.getApiLevel() < P) {
                _component_.performSaveInstanceState(outState);
                if (RuntimeEnvironment.getApiLevel() <= M) {
                    _component_.performStop();
                } else {
                    // API from N to O_MR1(both including)
                    _component_.performStop(true);
                }
            } else {
                _component_.performStop(true, "configurationChange");
                _component_.performSaveInstanceState(outState);
            }
            // 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 ? // No framework or user state.
            null : reflector(_NonConfigurationInstances_.class, nonConfigInstance).getActivity();
            _component_.performDestroy();
            makeActivityEligibleForGc();
            // 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(/* activityOptions= */
            null, /* 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;
}
Also used : ShadowViewRootImpl(org.robolectric.shadows.ShadowViewRootImpl) ViewRootImpl(android.view.ViewRootImpl) Configuration(android.content.res.Configuration) org.robolectric.shadows._Activity_(org.robolectric.shadows._Activity_) ShadowContextThemeWrapper(org.robolectric.shadows.ShadowContextThemeWrapper) Bundle(android.os.Bundle) ShadowActivity(org.robolectric.shadows.ShadowActivity)

Aggregations

Configuration (android.content.res.Configuration)1 Bundle (android.os.Bundle)1 ViewRootImpl (android.view.ViewRootImpl)1 ShadowActivity (org.robolectric.shadows.ShadowActivity)1 ShadowContextThemeWrapper (org.robolectric.shadows.ShadowContextThemeWrapper)1 ShadowViewRootImpl (org.robolectric.shadows.ShadowViewRootImpl)1 org.robolectric.shadows._Activity_ (org.robolectric.shadows._Activity_)1