1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.window; 18 19 import static android.view.Display.INVALID_DISPLAY; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.ResourcesManager; 24 import android.content.Context; 25 import android.content.pm.ActivityInfo; 26 import android.content.res.Configuration; 27 import android.graphics.Canvas; 28 import android.graphics.Rect; 29 import android.os.IBinder; 30 import android.view.Display; 31 import android.view.WindowManager; 32 33 /** 34 * A helper class to maintain {@link android.content.res.Configuration} related methods used both 35 * in {@link android.app.Activity} and {@link WindowContext}. 36 * 37 * @hide 38 */ 39 public class ConfigurationHelper { ConfigurationHelper()40 private ConfigurationHelper() {} 41 42 /** Ask text layout engine to free its caches if there is a locale change. */ freeTextLayoutCachesIfNeeded(int configDiff)43 public static void freeTextLayoutCachesIfNeeded(int configDiff) { 44 if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) { 45 Canvas.freeTextLayoutCaches(); 46 } 47 } 48 49 /** 50 * A helper method to filter out {@link ActivityInfo#CONFIG_SCREEN_SIZE} if the 51 * {@link Configuration#diffPublicOnly(Configuration) diff} of two {@link Configuration} 52 * doesn't cross the boundary. 53 * 54 * @see SizeConfigurationBuckets#filterDiff(int, Configuration, Configuration, 55 * SizeConfigurationBuckets) 56 */ diffPublicWithSizeBuckets(@ullable Configuration currentConfig, @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets)57 public static int diffPublicWithSizeBuckets(@Nullable Configuration currentConfig, 58 @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets) { 59 // If current configuration is null, it is definitely different from updated Configuration. 60 if (currentConfig == null) { 61 return 0xffffffff; 62 } 63 int publicDiff = currentConfig.diffPublicOnly(newConfig); 64 return SizeConfigurationBuckets.filterDiff(publicDiff, currentConfig, newConfig, buckets); 65 } 66 67 /** 68 * Returns {@code true} if the {@link android.content.res.Resources} associated with 69 * a {@code token} needs to be updated. 70 * 71 * @param token A {@link Context#getActivityToken() activity token} or 72 * {@link Context#getWindowContextToken() window context token} 73 * @param config The original {@link Configuration} 74 * @param newConfig The updated Configuration 75 * @param displayChanged a flag to indicate there's a display change 76 * @param configChanged a flag to indicate there's a Configuration change. 77 * 78 * @see ResourcesManager#updateResourcesForActivity(IBinder, Configuration, int) 79 */ shouldUpdateResources(IBinder token, @Nullable Configuration config, @NonNull Configuration newConfig, @NonNull Configuration overrideConfig, boolean displayChanged, @Nullable Boolean configChanged)80 public static boolean shouldUpdateResources(IBinder token, @Nullable Configuration config, 81 @NonNull Configuration newConfig, @NonNull Configuration overrideConfig, 82 boolean displayChanged, @Nullable Boolean configChanged) { 83 // The configuration has not yet been initialized. We should update it. 84 if (config == null) { 85 return true; 86 } 87 // If the token associated context is moved to another display, we should update the 88 // ResourcesKey. 89 if (displayChanged) { 90 return true; 91 } 92 // If the new config is the same as the config this Activity is already running with and 93 // the override config also didn't change, then don't update the Resources 94 if (!ResourcesManager.getInstance().isSameResourcesOverrideConfig(token, overrideConfig)) { 95 return true; 96 } 97 // If there's a update on WindowConfiguration#mBounds or maxBounds, we should update the 98 // Resources to make WindowMetrics API report the updated result. 99 if (shouldUpdateWindowMetricsBounds(config, newConfig)) { 100 return true; 101 } 102 return configChanged == null ? config.diff(newConfig) != 0 : configChanged; 103 } 104 105 /** 106 * Returns {@code true} if {@code displayId} is different from {@code newDisplayId}. 107 * Note that {@link Display#INVALID_DISPLAY} means no difference. 108 */ isDifferentDisplay(int displayId, int newDisplayId)109 public static boolean isDifferentDisplay(int displayId, int newDisplayId) { 110 return newDisplayId != INVALID_DISPLAY && displayId != newDisplayId; 111 } 112 113 // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl 114 // constructions. 115 /** 116 * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs 117 * should be updated. 118 * 119 * @see WindowManager#getCurrentWindowMetrics() 120 * @see WindowManager#getMaximumWindowMetrics() 121 */ shouldUpdateWindowMetricsBounds(@onNull Configuration currentConfig, @NonNull Configuration newConfig)122 private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig, 123 @NonNull Configuration newConfig) { 124 final Rect currentBounds = currentConfig.windowConfiguration.getBounds(); 125 final Rect newBounds = newConfig.windowConfiguration.getBounds(); 126 127 final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds(); 128 final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds(); 129 130 return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds); 131 } 132 } 133