Merge "Handle WindowProviderService#onConfigurationChanged" into sc-v2-dev am: 41fc06529b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14550549 Change-Id: I9d6656b2f4bd55a1d45bb1c3fba7eca29d44865c
This commit is contained in:
@@ -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.
|
||||
// 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 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.
|
||||
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++) {
|
||||
|
||||
@@ -38,5 +38,5 @@ interface ActivityThreadInternal {
|
||||
|
||||
Application getApplication();
|
||||
|
||||
ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities);
|
||||
ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
core/java/android/window/ConfigurationHelper.java
Normal file
132
core/java/android/window/ConfigurationHelper.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@
|
||||
*/
|
||||
package android.window;
|
||||
|
||||
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 android.annotation.NonNull;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.IWindowToken;
|
||||
@@ -33,7 +38,7 @@ import java.lang.ref.WeakReference;
|
||||
* {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}.
|
||||
*
|
||||
* @see WindowContext
|
||||
* @see android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, Bundle)
|
||||
* @see android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, Bundle)
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -46,11 +51,13 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
|
||||
private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();
|
||||
|
||||
private final Configuration mConfiguration = new Configuration();
|
||||
|
||||
/**
|
||||
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
|
||||
* can only attach one {@link Context}.
|
||||
* <p>This method must be called before invoking
|
||||
* {@link android.view.IWindowManager#registerWindowContextListener(IBinder, int, int,
|
||||
* {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int,
|
||||
* Bundle, boolean)}.<p/>
|
||||
*
|
||||
* @param context context to be attached
|
||||
@@ -61,6 +68,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
throw new IllegalStateException("Context is already attached.");
|
||||
}
|
||||
mContextRef = new WeakReference<>(context);
|
||||
mConfiguration.setTo(context.getResources().getConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,17 +77,34 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
final int currentDisplayId = context.getDisplayId();
|
||||
final boolean displayChanged = newDisplayId != currentDisplayId;
|
||||
final Configuration config = context.getResources().getConfiguration();
|
||||
final boolean configChanged = config.diff(newConfig) != 0;
|
||||
if (displayChanged || configChanged) {
|
||||
final boolean displayChanged = isDifferentDisplay(context.getDisplayId(), newDisplayId);
|
||||
final boolean shouldUpdateResources = shouldUpdateResources(this, mConfiguration,
|
||||
newConfig, newConfig /* overrideConfig */, displayChanged,
|
||||
null /* configChanged */);
|
||||
|
||||
if (shouldUpdateResources) {
|
||||
// TODO(ag/9789103): update resource manager logic to track non-activity tokens
|
||||
mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
|
||||
|
||||
if (context instanceof WindowContext) {
|
||||
ActivityThread.currentActivityThread().getHandler().post(
|
||||
() -> ((WindowContext) context).dispatchConfigurationChanged(newConfig));
|
||||
}
|
||||
|
||||
// Dispatch onConfigurationChanged only if there's a significant public change to
|
||||
// make it compatible with the original behavior.
|
||||
final Configuration[] sizeConfigurations = context.getResources()
|
||||
.getSizeConfigurations();
|
||||
final SizeConfigurationBuckets buckets = sizeConfigurations != null
|
||||
? new SizeConfigurationBuckets(sizeConfigurations) : null;
|
||||
final int diff = diffPublicWithSizeBuckets(mConfiguration, newConfig, buckets);
|
||||
|
||||
if (context instanceof WindowProviderService && diff != 0) {
|
||||
ActivityThread.currentActivityThread().getHandler().post(() ->
|
||||
((WindowProviderService) context).onConfigurationChanged(newConfig));
|
||||
}
|
||||
freeTextLayoutCachesIfNeeded(diff);
|
||||
mConfiguration.setTo(newConfig);
|
||||
}
|
||||
if (displayChanged) {
|
||||
context.updateDisplay(newDisplayId);
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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 com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.ResourcesManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Binder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationHelper}
|
||||
*
|
||||
* <p>Build/Install/Run:
|
||||
* atest FrameworksMockingCoreTests:ConfigurationHelperTest
|
||||
*
|
||||
* <p>This test class is a part of Window Manager Service tests and specified in
|
||||
* {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
public class ConfigurationHelperTest {
|
||||
MockitoSession mMockitoSession;
|
||||
ResourcesManager mResourcesManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mMockitoSession = mockitoSession()
|
||||
.strictness(Strictness.LENIENT)
|
||||
.spyStatic(ResourcesManager.class)
|
||||
.startMocking();
|
||||
doReturn(mock(ResourcesManager.class)).when(ResourcesManager::getInstance);
|
||||
mResourcesManager = ResourcesManager.getInstance();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mMockitoSession.finishMocking();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_NullConfig_ReturnsTrue() {
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), null /* config */,
|
||||
new Configuration(), new Configuration(), false /* displayChanged */,
|
||||
null /* configChanged */)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_DisplayChanged_ReturnsTrue() {
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), new Configuration(),
|
||||
new Configuration(), new Configuration(), true /* displayChanged */,
|
||||
null /* configChanged */)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_DifferentResources_ReturnsTrue() {
|
||||
doReturn(false).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
|
||||
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), new Configuration(),
|
||||
new Configuration(), new Configuration(), false /* displayChanged */,
|
||||
null /* configChanged */)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_DifferentBounds_ReturnsTrue() {
|
||||
doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
|
||||
|
||||
final Configuration config = new Configuration();
|
||||
config.windowConfiguration.setBounds(new Rect(0, 0, 10, 10));
|
||||
config.windowConfiguration.setMaxBounds(new Rect(0, 0, 20, 20));
|
||||
|
||||
final Configuration newConfig = new Configuration();
|
||||
newConfig.windowConfiguration.setBounds(new Rect(0, 0, 20, 20));
|
||||
newConfig.windowConfiguration.setMaxBounds(new Rect(0, 0, 20, 20));
|
||||
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
|
||||
new Configuration(), false /* displayChanged */, null /* configChanged */))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_SameConfig_ReturnsFalse() {
|
||||
doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
|
||||
|
||||
final Configuration config = new Configuration();
|
||||
final Configuration newConfig = new Configuration();
|
||||
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
|
||||
new Configuration(), false /* displayChanged */, null /* configChanged */))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_DifferentConfig_ReturnsTrue() {
|
||||
doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
|
||||
|
||||
final Configuration config = new Configuration();
|
||||
final Configuration newConfig = new Configuration();
|
||||
newConfig.setToDefaults();
|
||||
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
|
||||
new Configuration(), false /* displayChanged */, null /* configChanged */))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_DifferentNonPublicConfig_ReturnsTrue() {
|
||||
doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
|
||||
|
||||
final Configuration config = new Configuration();
|
||||
final Configuration newConfig = new Configuration();
|
||||
newConfig.windowConfiguration.setAppBounds(new Rect(0, 0, 10, 10));
|
||||
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
|
||||
new Configuration(), false /* displayChanged */, null /* configChanged */))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldUpdateResources_OverrideConfigChanged_ReturnsFalse() {
|
||||
doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
|
||||
|
||||
final Configuration config = new Configuration();
|
||||
final Configuration newConfig = new Configuration();
|
||||
final boolean configChanged = true;
|
||||
|
||||
assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
|
||||
new Configuration(), false /* displayChanged */, configChanged))
|
||||
.isEqualTo(configChanged);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ public final class FrameworksTestsFilter extends SelectTest {
|
||||
// Test specifications for FrameworksMockingCoreTests.
|
||||
"android.app.activity.ActivityThreadClientTest",
|
||||
"android.view.DisplayTest",
|
||||
"android.window.ConfigurationHelperTest",
|
||||
// Test specifications for FrameworksCoreTests.
|
||||
"android.app.servertransaction.", // all tests under the package.
|
||||
"android.view.CutoutSpecificationTest",
|
||||
@@ -59,10 +60,8 @@ public final class FrameworksTestsFilter extends SelectTest {
|
||||
"android.view.RoundedCornersTest",
|
||||
"android.view.WindowMetricsTest",
|
||||
"android.view.PendingInsetsControllerTest",
|
||||
"android.window.WindowContextTest",
|
||||
"android.window.WindowMetricsHelperTest",
|
||||
"android.window.", // all tests under the package.
|
||||
"android.app.activity.ActivityThreadTest",
|
||||
"android.window.WindowContextControllerTest"
|
||||
};
|
||||
|
||||
public FrameworksTestsFilter(Bundle testArgs) {
|
||||
|
||||
Reference in New Issue
Block a user