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

Commit 41fc0652 authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Handle WindowProviderService#onConfigurationChanged" into sc-v2-dev

parents 52551c91 0a3126f4
Loading
Loading
Loading
Loading
+35 −64
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package android.app;

import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ConfigurationController.createNewConfigAndUpdateIfNotNull;
import static android.app.ConfigurationController.freeTextLayoutCachesIfNeeded;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
@@ -31,6 +30,10 @@ 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.view.Display.INVALID_DISPLAY;
import static android.window.ConfigurationHelper.diffPublicWithSizeBuckets;
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;

@@ -91,7 +94,6 @@ import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.HardwareRenderer;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
import android.inputmethodservice.InputMethodService;
@@ -186,6 +188,7 @@ import android.webkit.WebView;
import android.window.SizeConfigurationBuckets;
import android.window.SplashScreen;
import android.window.SplashScreenView;
import android.window.WindowProviderService;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -5756,7 +5759,7 @@ public final class ActivityThread extends ClientTransactionHandler
    }

    @Override
    public ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities) {
    public ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts) {
        ArrayList<ComponentCallbacks2> callbacks
                = new ArrayList<ComponentCallbacks2>();

@@ -5765,7 +5768,7 @@ public final class ActivityThread extends ClientTransactionHandler
            for (int i=0; i<NAPP; i++) {
                callbacks.add(mAllApplications.get(i));
            }
            if (includeActivities) {
            if (includeUiContexts) {
                for (int i = mActivities.size() - 1; i >= 0; i--) {
                    final Activity a = mActivities.valueAt(i).activity;
                    if (a != null && !a.mFinished) {
@@ -5775,11 +5778,15 @@ public final class ActivityThread extends ClientTransactionHandler
            }
            final int NSVC = mServices.size();
            for (int i=0; i<NSVC; i++) {
                final ComponentCallbacks2 serviceComp = mServices.valueAt(i);
                if (serviceComp instanceof InputMethodService) {
                final Service service = mServices.valueAt(i);
                if (service instanceof InputMethodService) {
                    mHasImeComponent = true;
                }
                callbacks.add(serviceComp);
                // If {@code includeUiContext} is set to false, WindowProviderService should not be
                // collected because WindowProviderService is a UI Context.
                if (includeUiContexts || !(service instanceof WindowProviderService)) {
                    callbacks.add(service);
                }
            }
        }
        synchronized (mProviderMap) {
@@ -5834,35 +5841,26 @@ public final class ActivityThread extends ClientTransactionHandler
        // change callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition
        handleWindowingModeChangeIfNeeded(activity, newConfig);

        final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId);
        boolean shouldReportChange = false;
        if (activity.mCurrentConfig == null) {
            shouldReportChange = true;
        } else {
            // If the new config is the same as the config this Activity is already running with and
            // the override config also didn't change, then don't bother calling
            // onConfigurationChanged.
        final boolean movedToDifferentDisplay = isDifferentDisplay(activity.getDisplayId(),
                displayId);
        final SizeConfigurationBuckets buckets = getActivityClient(activityToken)
                .mSizeConfigurations;
        final int diff = diffPublicWithSizeBuckets(activity.mCurrentConfig,
                newConfig, buckets);
        final boolean hasPublicConfigChange = diff != 0;
        // TODO(b/173090263): Use diff instead after the improvement of AssetManager and
        // ResourcesImpl constructions.
            int diff = activity.mCurrentConfig.diffPublicOnly(newConfig);
            final ActivityClientRecord cr = getActivityClient(activityToken);
            diff = SizeConfigurationBuckets.filterDiff(diff, activity.mCurrentConfig, newConfig,
                    cr != null ? cr.mSizeConfigurations : null);

            if (diff == 0) {
                if (!shouldUpdateWindowMetricsBounds(activity.mCurrentConfig, newConfig)
                        && !movedToDifferentDisplay
                        && mResourcesManager.isSameResourcesOverrideConfig(
                                activityToken, amOverrideConfig)) {
                    // Nothing significant, don't proceed with updating and reporting.
                    return null;
                }
            } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
        final boolean shouldUpdateResources = hasPublicConfigChange
                || shouldUpdateResources(activityToken, activity.mCurrentConfig, newConfig,
                amOverrideConfig, movedToDifferentDisplay, hasPublicConfigChange);
        final boolean shouldReportChange = hasPublicConfigChange
                // If this activity doesn't handle any of the config changes, then don't bother
                // calling onConfigurationChanged. Otherwise, report to the activity for the
                // changes.
                shouldReportChange = true;
            }
                && (~activity.mActivityInfo.getRealConfigChanged() & diff) == 0;
        // Nothing significant, don't proceed with updating and reporting.
        if (!shouldUpdateResources) {
            return null;
        }

        // Propagate the configuration change to ResourcesManager and Activity.
@@ -5913,26 +5911,6 @@ public final class ActivityThread extends ClientTransactionHandler
        return configToReport;
    }

    // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl
    // constructions.
    /**
     * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs
     * should be updated.
     *
     * @see WindowManager#getCurrentWindowMetrics()
     * @see WindowManager#getMaximumWindowMetrics()
     */
    private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
            @NonNull Configuration newConfig) {
        final Rect currentBounds = currentConfig.windowConfiguration.getBounds();
        final Rect newBounds = newConfig.windowConfiguration.getBounds();

        final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds();
        final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds();

        return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds);
    }

    public final void applyConfigurationToResources(Configuration config) {
        synchronized (mResourcesManager) {
            mResourcesManager.applyConfigurationToResources(config, null);
@@ -6080,7 +6058,8 @@ public final class ActivityThread extends ClientTransactionHandler
            // display.
            displayId = r.activity.getDisplayId();
        }
        final boolean movedToDifferentDisplay = isDifferentDisplay(r.activity, displayId);
        final boolean movedToDifferentDisplay = isDifferentDisplay(
                r.activity.getDisplayId(), displayId);
        if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
                && !movedToDifferentDisplay) {
            if (DEBUG_CONFIGURATION) {
@@ -6116,14 +6095,6 @@ public final class ActivityThread extends ClientTransactionHandler
        mSomeActivitiesChanged = true;
    }

    /**
     * Checks if the display id of activity is different from the given one. Note that
     * {@link Display#INVALID_DISPLAY} means no difference.
     */
    private static boolean isDifferentDisplay(@NonNull Activity activity, int displayId) {
        return displayId != INVALID_DISPLAY && displayId != activity.getDisplayId();
    }

    final void handleProfilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
        if (start) {
            try {
@@ -6301,7 +6272,7 @@ public final class ActivityThread extends ClientTransactionHandler

    final void handleLowMemory() {
        final ArrayList<ComponentCallbacks2> callbacks =
                collectComponentCallbacks(true /* includeActivities */);
                collectComponentCallbacks(true /* includeUiContexts */);

        final int N = callbacks.size();
        for (int i=0; i<N; i++) {
@@ -6334,7 +6305,7 @@ public final class ActivityThread extends ClientTransactionHandler
        }

        final ArrayList<ComponentCallbacks2> callbacks =
                collectComponentCallbacks(true /* includeActivities */);
                collectComponentCallbacks(true /* includeUiContexts */);

        final int N = callbacks.size();
        for (int i = 0; i < N; i++) {
+1 −1
Original line number Diff line number Diff line
@@ -38,5 +38,5 @@ interface ActivityThreadInternal {

    Application getApplication();

    ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities);
    ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts);
}
+2 −15
Original line number Diff line number Diff line
@@ -17,17 +17,16 @@
package android.app;

import static android.app.ActivityThread.DEBUG_CONFIGURATION;
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.HardwareRenderer;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
@@ -228,7 +227,7 @@ class ConfigurationController {
        }

        final ArrayList<ComponentCallbacks2> callbacks =
                mActivityThread.collectComponentCallbacks(false /* includeActivities */);
                mActivityThread.collectComponentCallbacks(false /* includeUiContexts */);

        freeTextLayoutCachesIfNeeded(configDiff);

@@ -326,16 +325,4 @@ class ConfigurationController {
        return newConfig;
    }

    /** Ask test layout engine to free its caches if there is a locale change. */
    static void freeTextLayoutCachesIfNeeded(int configDiff) {
        if (configDiff != 0) {
            boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0);
            if (hasLocaleConfigChange) {
                Canvas.freeTextLayoutCaches();
                if (DEBUG_CONFIGURATION) {
                    Slog.v(TAG, "Cleared TextLayout Caches");
                }
            }
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -730,7 +730,7 @@ public class ResourcesManager {
     * @return true if activity resources override config matches the provided one or they are both
     *         null, false otherwise.
     */
    boolean isSameResourcesOverrideConfig(@Nullable IBinder activityToken,
    public boolean isSameResourcesOverrideConfig(@Nullable IBinder activityToken,
            @Nullable Configuration overrideConfig) {
        synchronized (mLock) {
            final ActivityResources activityResources
+132 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.window;

import static android.view.Display.INVALID_DISPLAY;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ResourcesManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.Display;
import android.view.WindowManager;

/**
 * A helper class to maintain {@link android.content.res.Configuration} related methods used both
 * in {@link android.app.Activity} and {@link WindowContext}.
 *
 * @hide
 */
public class ConfigurationHelper {
    private ConfigurationHelper() {}

    /** Ask text layout engine to free its caches if there is a locale change. */
    public static void freeTextLayoutCachesIfNeeded(int configDiff) {
        if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
            Canvas.freeTextLayoutCaches();
        }
    }

    /**
     * A helper method to filter out {@link ActivityInfo#CONFIG_SCREEN_SIZE} if the
     * {@link Configuration#diffPublicOnly(Configuration) diff} of two {@link Configuration}
     * doesn't cross the boundary.
     *
     * @see SizeConfigurationBuckets#filterDiff(int, Configuration, Configuration,
     * SizeConfigurationBuckets)
     */
    public static int diffPublicWithSizeBuckets(@Nullable Configuration currentConfig,
            @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets) {
        // If current configuration is null, it is definitely different from updated Configuration.
        if (currentConfig == null) {
            return 0xffffffff;
        }
        int publicDiff = currentConfig.diffPublicOnly(newConfig);
        return SizeConfigurationBuckets.filterDiff(publicDiff, currentConfig, newConfig, buckets);
    }

    /**
     * Returns {@code true} if the {@link android.content.res.Resources} associated with
     * a {@code token} needs to be updated.
     *
     * @param token A {@link Context#getActivityToken() activity token} or
     * {@link Context#getWindowContextToken() window context token}
     * @param config The original {@link Configuration}
     * @param newConfig The updated Configuration
     * @param displayChanged a flag to indicate there's a display change
     * @param configChanged a flag to indicate there's a Configuration change.
     *
     * @see ResourcesManager#updateResourcesForActivity(IBinder, Configuration, int)
     */
    public static boolean shouldUpdateResources(IBinder token, @Nullable Configuration config,
            @NonNull Configuration newConfig, @NonNull Configuration overrideConfig,
            boolean displayChanged, @Nullable Boolean configChanged) {
        // The configuration has not yet been initialized. We should update it.
        if (config == null) {
            return true;
        }
        // If the token associated context is moved to another display, we should update the
        // ResourcesKey.
        if (displayChanged) {
            return true;
        }
        // If the new config is the same as the config this Activity is already running with and
        // the override config also didn't change, then don't update the Resources
        if (!ResourcesManager.getInstance().isSameResourcesOverrideConfig(token, overrideConfig)) {
            return true;
        }
        // If there's a update on WindowConfiguration#mBounds or maxBounds, we should update the
        // Resources to make WindowMetrics API report the updated result.
        if (shouldUpdateWindowMetricsBounds(config, newConfig)) {
            return true;
        }
        return configChanged == null ? config.diff(newConfig) != 0 : configChanged;
    }

    /**
     * Returns {@code true} if {@code displayId} is different from {@code newDisplayId}.
     * Note that {@link Display#INVALID_DISPLAY} means no difference.
     */
    public static boolean isDifferentDisplay(int displayId, int newDisplayId) {
        return newDisplayId != INVALID_DISPLAY && displayId != newDisplayId;
    }

    // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl
    // constructions.
    /**
     * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs
     * should be updated.
     *
     * @see WindowManager#getCurrentWindowMetrics()
     * @see WindowManager#getMaximumWindowMetrics()
     */
    private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
            @NonNull Configuration newConfig) {
        final Rect currentBounds = currentConfig.windowConfiguration.getBounds();
        final Rect newBounds = newConfig.windowConfiguration.getBounds();

        final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds();
        final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds();

        return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds);
    }
}
Loading