Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c3731e6 authored by William Xiao's avatar William Xiao
Browse files

Always send configuration change if only desk uiMode changed

Devices with config_skipActivityRelaunchWhenDocking do not relaunch
activities when docking for a better user experience, but should
still send onConfigurationChanged to activities. While some paths in
the logic of ActivityThread always send onConfigurationChanged no
matter what, not all do.

This CL patches the logic deciding whether or not to send
onConfigurationChanged to act as if the activity specified that it
would handle uiMode changes so that onConfigurationChanged will
always be sent as expected.

Bug: 274944389
Bug: 295876429
Bug: 294255156
Test: atest CtsWindowManagerDeviceOther:DockConfigChangeTests --iterations
      Also manually verified on device that configuration changes are
      always sent to a test activity on dock/undock
Change-Id: Ib4dfcf9ce92538b554935de52850c7514875245c
parent 503df176
Loading
Loading
Loading
Loading
+37 −3
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
@@ -206,6 +208,7 @@ import android.window.WindowContextInfo;
import android.window.WindowProviderService;
import android.window.WindowTokenClientController;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
@@ -6099,9 +6102,21 @@ public final class ActivityThread extends ClientTransactionHandler
        final boolean shouldUpdateResources = hasPublicResConfigChange
                || shouldUpdateResources(activityToken, currentResConfig, newConfig,
                amOverrideConfig, movedToDifferentDisplay, hasPublicResConfigChange);
        final boolean shouldReportChange = shouldReportChange(
                activity.mCurrentConfig, newConfig, r.mSizeConfigurations,
                activity.mActivityInfo.getRealConfigChanged(), alwaysReportChange);

        // TODO(b/274944389): remove once a longer-term solution is implemented.
        boolean skipActivityRelaunchWhenDocking = activity.getResources().getBoolean(
                R.bool.config_skipActivityRelaunchWhenDocking);
        int handledConfigChanges = activity.mActivityInfo.getRealConfigChanged();
        if (skipActivityRelaunchWhenDocking && onlyDeskInUiModeChanged(activity.mCurrentConfig,
                newConfig)) {
            // If we're not relaunching this activity when docking, we should send the configuration
            // changed event. Pretend as if the activity is handling uiMode config changes in its
            // manifest so that we'll report any dock changes.
            handledConfigChanges |= ActivityInfo.CONFIG_UI_MODE;
        }

        final boolean shouldReportChange = shouldReportChange(activity.mCurrentConfig, newConfig,
                r.mSizeConfigurations, handledConfigChanges, alwaysReportChange);
        // Nothing significant, don't proceed with updating and reporting.
        if (!shouldUpdateResources && !shouldReportChange) {
            return null;
@@ -6147,6 +6162,25 @@ public final class ActivityThread extends ClientTransactionHandler
        return configToReport;
    }

    /**
     * Returns true if the uiMode configuration changed, and desk mode
     * ({@link android.content.res.Configuration#UI_MODE_TYPE_DESK}) was the only change to uiMode.
     */
    private boolean onlyDeskInUiModeChanged(Configuration oldConfig, Configuration newConfig) {
        boolean deskModeChanged = isInDeskUiMode(oldConfig) != isInDeskUiMode(newConfig);

        // UI mode contains fields other than the UI mode type, so determine if any other fields
        // changed.
        boolean uiModeOtherFieldsChanged =
                (oldConfig.uiMode & ~UI_MODE_TYPE_MASK) != (newConfig.uiMode & ~UI_MODE_TYPE_MASK);

        return deskModeChanged && !uiModeOtherFieldsChanged;
    }

    private static boolean isInDeskUiMode(Configuration config) {
        return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_DESK;
    }

    /**
     * Returns {@code true} if {@link Activity#onConfigurationChanged(Configuration)} should be
     * dispatched.