From e810bc539e0d958c9041a8e1eb13301347644ced Mon Sep 17 00:00:00 2001 From: Darryl L Johnson Date: Mon, 27 Apr 2020 00:36:25 -0700 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 change fixes the issue by applying the activity's override configuration on top of the app config before updating the display adjustments. Note: This is a slight revert/rework of Ib3ee007bc Fixes: 148639826 Test: ActivityThreadTest#testHandleConfigurationChanged_DoesntOverrideActivityConfig Change-Id: I08a5bc29443fbdefbca791240aeaff8f138b8756 --- core/java/android/app/ResourcesManager.java | 24 ++++++-- .../app/activity/ActivityThreadTest.java | 55 +++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 47ccc2f0badbe..106f8ac92d05e 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -1109,10 +1109,16 @@ public class ResourcesManager { Slog.v(TAG, "Changing resources " + resourcesImpl + " config to: " + config); } - int displayId = key.mDisplayId; - final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); + tmpConfig.setTo(config); + // Apply the override configuration before setting the display adjustments to ensure that + // the process config does not override activity display adjustments. + final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); + if (hasOverrideConfiguration) { + tmpConfig.updateFrom(key.mOverrideConfiguration); + } + // 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 // update internally. @@ -1121,17 +1127,23 @@ public class ResourcesManager { daj = new DisplayAdjustments(daj); daj.setCompatibilityInfo(compat); } + + final int displayId = key.mDisplayId; if (displayId == Display.DEFAULT_DISPLAY) { - daj.setConfiguration(config); + daj.setConfiguration(tmpConfig); } DisplayMetrics dm = getDisplayMetrics(displayId, daj); if (displayId != Display.DEFAULT_DISPLAY) { applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); + + // Re-apply the override configuration to ensure that configuration contexts based on + // a display context (ex: createDisplayContext().createConfigurationContext()) have the + // correct override. + if (hasOverrideConfiguration) { + tmpConfig.updateFrom(key.mOverrideConfiguration); + } } - if (hasOverrideConfiguration) { - tmpConfig.updateFrom(key.mOverrideConfiguration); - } 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 34417e68f11c9..a93dacf470504 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -44,8 +44,11 @@ import android.app.servertransaction.StopActivityItem; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.IBinder; +import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.view.Display; import android.view.View; @@ -366,6 +369,58 @@ public class ActivityThreadTest { }); } + @Test + public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() { + 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());