From 8efbbe751fa5167d2a776c3acd24d9eb644ad4a9 Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Mon, 10 Feb 2020 17:25:30 -0800 Subject: [PATCH] Don't override activity display adjustments with app config When process configuration was applied on the client side it accidentally applied an override to display adjustments in resources for all ResourceImpl objects. This resulted in resources of activities having incorrect display adjustments and reporting incorrect display size. This CL fixes the issue by updating the applied config with the activity override. It also removes ResourcesManager#applyNonDefaultDisplayMetricsToConfiguration, which is no longer needed on the client side since the server-side is fully multi-display aware. Bug: 148639826 Test: ActivityThreadTest#testHandleConfigurationChangedDoesntOverrideActivityConfig Test: AppConfigurationTests#testDisplaySizeInSplitScreen Change-Id: Ib3ee007bcccd11451556b66274de4257cba082d4 --- core/java/android/app/ResourcesManager.java | 47 +++------------- .../app/activity/ActivityThreadTest.java | 55 +++++++++++++++++++ 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 81671c349cbd1..9f5dee98acb7d 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -250,28 +250,6 @@ public class ResourcesManager { return dm; } - private static void applyNonDefaultDisplayMetricsToConfiguration( - @NonNull DisplayMetrics dm, @NonNull Configuration config) { - config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; - config.densityDpi = dm.densityDpi; - config.screenWidthDp = (int) (dm.widthPixels / dm.density); - config.screenHeightDp = (int) (dm.heightPixels / dm.density); - int sl = Configuration.resetScreenLayout(config.screenLayout); - if (dm.widthPixels > dm.heightPixels) { - config.orientation = Configuration.ORIENTATION_LANDSCAPE; - config.screenLayout = Configuration.reduceScreenLayout(sl, - config.screenWidthDp, config.screenHeightDp); - } else { - config.orientation = Configuration.ORIENTATION_PORTRAIT; - config.screenLayout = Configuration.reduceScreenLayout(sl, - config.screenHeightDp, config.screenWidthDp); - } - config.smallestScreenWidthDp = Math.min(config.screenWidthDp, config.screenHeightDp); - config.compatScreenWidthDp = config.screenWidthDp; - config.compatScreenHeightDp = config.screenHeightDp; - config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp; - } - public boolean applyCompatConfigurationLocked(int displayDensity, @NonNull Configuration compatConfiguration) { if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) { @@ -519,17 +497,11 @@ public class ResourcesManager { private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) { Configuration config; - final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY); final boolean hasOverrideConfig = key.hasOverrideConfiguration(); - if (!isDefaultDisplay || hasOverrideConfig) { + if (hasOverrideConfig) { config = new Configuration(getConfiguration()); - if (!isDefaultDisplay) { - applyNonDefaultDisplayMetricsToConfiguration(dm, config); - } - if (hasOverrideConfig) { - config.updateFrom(key.mOverrideConfiguration); - if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration); - } + config.updateFrom(key.mOverrideConfiguration); + if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration); } else { config = getConfiguration(); } @@ -1110,8 +1082,6 @@ public class ResourcesManager { + resourcesImpl + " config to: " + config); } int displayId = key.mDisplayId; - final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); - tmpConfig.setTo(config); // Get new DisplayMetrics based on the DisplayAdjustments given to the ResourcesImpl. Update // a copy if the CompatibilityInfo changed, because the ResourcesImpl object will handle the @@ -1121,15 +1091,12 @@ public class ResourcesManager { daj = new DisplayAdjustments(daj); daj.setCompatibilityInfo(compat); } - daj.setConfiguration(config); - DisplayMetrics dm = getDisplayMetrics(displayId, daj); - if (displayId != Display.DEFAULT_DISPLAY) { - applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); - } - - if (hasOverrideConfiguration) { + tmpConfig.setTo(config); + if (key.hasOverrideConfiguration()) { tmpConfig.updateFrom(key.mOverrideConfiguration); } + daj.setConfiguration(tmpConfig); + DisplayMetrics dm = getDisplayMetrics(displayId, daj); resourcesImpl.updateConfiguration(tmpConfig, dm, compat); } diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index c328d720426d1..90d8bab842588 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -40,7 +40,10 @@ import android.app.servertransaction.ResumeActivityItem; import android.app.servertransaction.StopActivityItem; import android.content.Intent; import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Rect; import android.os.IBinder; +import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.view.Display; import android.view.View; @@ -306,6 +309,58 @@ public class ActivityThreadTest { assertEquals(400, activity.mConfig.smallestScreenWidthDp); } + @Test + public void testHandleConfigurationChangedDoesntOverrideActivityConfig() { + final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final Configuration oldActivityConfig = + new Configuration(activity.getResources().getConfiguration()); + final DisplayMetrics oldActivityMetrics = new DisplayMetrics(); + activity.getDisplay().getMetrics(oldActivityMetrics); + final Resources oldAppResources = activity.getApplication().getResources(); + final Configuration oldAppConfig = + new Configuration(oldAppResources.getConfiguration()); + final DisplayMetrics oldApplicationMetrics = new DisplayMetrics(); + oldApplicationMetrics.setTo(oldAppResources.getDisplayMetrics()); + assertEquals("Process config must match the top activity config by default", + 0, oldActivityConfig.diffPublicOnly(oldAppConfig)); + assertEquals("Process config must match the top activity config by default", + oldActivityMetrics, oldApplicationMetrics); + + // Update the application configuration separately from activity config + final Configuration newAppConfig = new Configuration(oldAppConfig); + newAppConfig.densityDpi += 100; + newAppConfig.screenHeightDp += 100; + final Rect newBounds = new Rect(newAppConfig.windowConfiguration.getAppBounds()); + newBounds.bottom += 100; + newAppConfig.windowConfiguration.setAppBounds(newBounds); + newAppConfig.windowConfiguration.setBounds(newBounds); + newAppConfig.seq++; + + final ActivityThread activityThread = activity.getActivityThread(); + activityThread.handleConfigurationChanged(newAppConfig); + + // Verify that application config update was applied, but didn't change activity config. + assertEquals("Activity config must not change if the process config changes", + oldActivityConfig, activity.getResources().getConfiguration()); + + final DisplayMetrics newActivityMetrics = new DisplayMetrics(); + activity.getDisplay().getMetrics(newActivityMetrics); + assertEquals("Activity display size must not change if the process config changes", + oldActivityMetrics, newActivityMetrics); + final Resources newAppResources = activity.getApplication().getResources(); + assertEquals("Application config must be updated", + newAppConfig, newAppResources.getConfiguration()); + final DisplayMetrics newApplicationMetrics = new DisplayMetrics(); + newApplicationMetrics.setTo(newAppResources.getDisplayMetrics()); + assertNotEquals("Application display size must be updated after config update", + oldApplicationMetrics, newApplicationMetrics); + assertNotEquals("Application display size must be updated after config update", + newActivityMetrics, newApplicationMetrics); + }); + } + @Test public void testResumeAfterNewIntent() { final Activity activity = mActivityTestRule.launchActivity(new Intent());