| /* |
| * 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); |
| } |
| } |