diff options
8 files changed, 203 insertions, 39 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 4fc894ca9ff4..16bfaf506ab2 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -135,8 +135,29 @@ interface IWindowManager int getDisplayIdByUniqueId(String uniqueId); @EnforcePermission("WRITE_SECURE_SETTINGS") void setForcedDisplayDensityForUser(int displayId, int density, int userId); + /** + * Clears forced density and forced density ratio in DisplayWindowSettings for the given + * displayId. + * + * @param displayId Id of the display. + * @param userId Id of the user. + */ @EnforcePermission("WRITE_SECURE_SETTINGS") void clearForcedDisplayDensityForUser(int displayId, int userId); + /** + * Sets display forced density ratio and forced density in DisplayWindowSettings for + * the given displayId. Ratio is used to update forced density to persist display size when + * resolution change happens. Use {@link #setForcedDisplayDensityForUser} when there is no need + * to handle resolution changes for the display. If setForcedDisplayDensityForUser is used after, + * this the ratio will be updated to use the last set forced density. Use + * {@link #clearForcedDisplayDensityForUser} to reset. + * + * @param displayId Id of the display. + * @param ratio The ratio of forced density to the default density. + * @param userId Id of the user. + */ + @EnforcePermission("WRITE_SECURE_SETTINGS") + void setForcedDisplayDensityRatio(int displayId, float ratio, int userId); /** * Sets settings for a specific user in a batch to minimize configuration updates. diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java index 985599c952d1..0d5f66794e3b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java @@ -97,6 +97,12 @@ public class DisplayDensityUtils { @Nullable private final int[] mValues; + /** + * The density values before rounding to an integer. + */ + @Nullable + private final float[] mFloatValues; + private final int mDefaultDensity; private final int mCurrentIndex; @@ -124,6 +130,7 @@ public class DisplayDensityUtils { Log.w(LOG_TAG, "Cannot fetch display info for the default display"); mEntries = null; mValues = null; + mFloatValues = null; mDefaultDensity = 0; mCurrentIndex = -1; return; @@ -154,6 +161,7 @@ public class DisplayDensityUtils { Log.w(LOG_TAG, "No display satisfies the predicate"); mEntries = null; mValues = null; + mFloatValues = null; mDefaultDensity = 0; mCurrentIndex = -1; return; @@ -165,6 +173,7 @@ public class DisplayDensityUtils { Log.w(LOG_TAG, "Cannot fetch default density for display " + idOfSmallestDisplay); mEntries = null; mValues = null; + mFloatValues = null; mDefaultDensity = 0; mCurrentIndex = -1; return; @@ -197,18 +206,25 @@ public class DisplayDensityUtils { String[] entries = new String[1 + numSmaller + numLarger]; int[] values = new int[entries.length]; + float[] valuesFloat = new float[entries.length]; int curIndex = 0; if (numSmaller > 0) { final float interval = (1 - minScale) / numSmaller; for (int i = numSmaller - 1; i >= 0; i--) { + // Save the float density value before rounding to be used to set the density ratio + // of overridden density to default density in WM. + final float densityFloat = defaultDensity * (1 - (i + 1) * interval); // Round down to a multiple of 2 by truncating the low bit. - final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1; + // LINT.IfChange + final int density = ((int) densityFloat) & ~1; + // LINT.ThenChange(/services/core/java/com/android/server/wm/DisplayContent.java:getBaseDensityFromRatio) if (currentDensity == density) { currentDensityIndex = curIndex; } - entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]); values[curIndex] = density; + valuesFloat[curIndex] = densityFloat; + entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]); curIndex++; } } @@ -217,18 +233,25 @@ public class DisplayDensityUtils { currentDensityIndex = curIndex; } values[curIndex] = defaultDensity; + valuesFloat[curIndex] = (float) defaultDensity; entries[curIndex] = res.getString(SUMMARY_DEFAULT); curIndex++; if (numLarger > 0) { final float interval = (maxScale - 1) / numLarger; for (int i = 0; i < numLarger; i++) { + // Save the float density value before rounding to be used to set the density ratio + // of overridden density to default density in WM. + final float densityFloat = defaultDensity * (1 + (i + 1) * interval); // Round down to a multiple of 2 by truncating the low bit. - final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1; + // LINT.IfChange + final int density = ((int) densityFloat) & ~1; + // LINT.ThenChange(/services/core/java/com/android/server/wm/DisplayContent.java:getBaseDensityFromRatio) if (currentDensity == density) { currentDensityIndex = curIndex; } values[curIndex] = density; + valuesFloat[curIndex] = densityFloat; entries[curIndex] = res.getString(SUMMARIES_LARGER[i]); curIndex++; } @@ -244,6 +267,9 @@ public class DisplayDensityUtils { values = Arrays.copyOf(values, newLength); values[curIndex] = currentDensity; + valuesFloat = Arrays.copyOf(valuesFloat, newLength); + valuesFloat[curIndex] = (float) currentDensity; + entries = Arrays.copyOf(entries, newLength); entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity); @@ -254,6 +280,7 @@ public class DisplayDensityUtils { mCurrentIndex = displayIndex; mEntries = entries; mValues = values; + mFloatValues = valuesFloat; } @Nullable @@ -348,7 +375,14 @@ public class DisplayDensityUtils { } final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); - wm.setForcedDisplayDensityForUser(displayId, mValues[index], userId); + // Only set the ratio for external displays as Settings uses + // ScreenResolutionFragment to handle density update for internal display. + if (info.type == Display.TYPE_EXTERNAL) { + wm.setForcedDisplayDensityRatio(displayId, + mFloatValues[index] / mDefaultDensity, userId); + } else { + wm.setForcedDisplayDensityForUser(displayId, mValues[index], userId); + } } } catch (RemoteException exc) { Log.w(LOG_TAG, "Unable to save forced display density setting"); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index afacae8d0c13..e80a5d43c072 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -46,7 +46,6 @@ import static android.view.Display.FLAG_PRIVATE; import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.STATE_UNKNOWN; -import static android.view.Display.TYPE_EXTERNAL; import static android.view.Display.isSuspendedState; import static android.view.InsetsSource.ID_IME; import static android.view.Surface.ROTATION_0; @@ -432,9 +431,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** * Ratio between overridden display density for current user and the initial display density, - * used only for external displays. + * used for updating the base density when resolution change happens to preserve display size. */ - float mExternalDisplayForcedDensityRatio = 0.0f; + float mForcedDisplayDensityRatio = 0.0f; boolean mIsDensityForced = false; /** @@ -3119,6 +3118,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mBaseRoundedCorners = loadRoundedCorners(baseWidth, baseHeight); } + // Update the base density if there is a forced density ratio. + if (DesktopExperienceFlags.ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS.isTrue() + && mForcedDisplayDensityRatio != 0.0f) { + mBaseDisplayDensity = getBaseDensityFromRatio(); + } + if (mMaxUiWidth > 0 && mBaseDisplayWidth > mMaxUiWidth) { final float ratio = mMaxUiWidth / (float) mBaseDisplayWidth; mBaseDisplayHeight = (int) (mBaseDisplayHeight * ratio); @@ -3136,18 +3141,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp + mBaseDisplayHeight + " on display:" + getDisplayId()); } } - // Update the base density if there is a forced density ratio. - if (DesktopExperienceFlags.ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS.isTrue() - && mIsDensityForced && mExternalDisplayForcedDensityRatio != 0.0f) { - mBaseDisplayDensity = (int) - (mInitialDisplayDensity * mExternalDisplayForcedDensityRatio + 0.5); - } if (mDisplayReady && !mDisplayPolicy.shouldKeepCurrentDecorInsets()) { mDisplayPolicy.mDecorInsets.invalidate(); } } /** + * Returns the forced density from forcedDensityRatio if the ratio is valid by rounding the + * density down to an even number. Returns the initial density if the ratio is 0. + */ + private int getBaseDensityFromRatio() { + return (mForcedDisplayDensityRatio != 0.0f) + ? ((int) (mInitialDisplayDensity * mForcedDisplayDensityRatio)) & ~1 + : mInitialDisplayDensity; + } + + /** * Forces this display to use the specified density. * * @param density The density in DPI to use. If the value equals to initial density, the setting @@ -3171,15 +3180,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (density == getInitialDisplayDensity()) { density = 0; } - // Save the new density ratio to settings for external displays. - if (DesktopExperienceFlags.ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS.isTrue() - && mDisplayInfo.type == TYPE_EXTERNAL) { - mExternalDisplayForcedDensityRatio = (float) - mBaseDisplayDensity / getInitialDisplayDensity(); + mWmService.mDisplayWindowSettings.setForcedDensity(getDisplayInfo(), density, userId); + } + + void setForcedDensityRatio(float ratio, int userId) { + // Save the new density ratio to settings and update forced density with the ratio. + if (DesktopExperienceFlags.ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS.isTrue()) { + mForcedDisplayDensityRatio = ratio; mWmService.mDisplayWindowSettings.setForcedDensityRatio(getDisplayInfo(), - mExternalDisplayForcedDensityRatio); + mForcedDisplayDensityRatio); + + // Set forced density from ratio. + setForcedDensity(getBaseDensityFromRatio(), userId); } - mWmService.mDisplayWindowSettings.setForcedDensity(getDisplayInfo(), density, userId); } /** @param mode {@link #FORCE_SCALING_MODE_AUTO} or {@link #FORCE_SCALING_MODE_DISABLED}. */ diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index 56579206566f..2818d79a40ad 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -391,7 +391,7 @@ class DisplayWindowSettings { final int density = hasDensityOverride ? settings.mForcedDensity : dc.getInitialDisplayDensity(); if (hasDensityOverrideRatio) { - dc.mExternalDisplayForcedDensityRatio = settings.mForcedDensityRatio; + dc.mForcedDisplayDensityRatio = settings.mForcedDensityRatio; } dc.updateBaseDisplayMetrics(width, height, density, dc.mBaseDisplayPhysicalXDpi, diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ff43d72c5a07..74b27dd1c2e4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6212,6 +6212,10 @@ public class WindowManagerService extends IWindowManager.Stub final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { + // Clear forced display density ratio + setForcedDisplayDensityRatioInternal(displayId, 0.0f, userId); + + // Clear forced display density final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.setForcedDensity(displayContent.getInitialDisplayDensity(), @@ -6236,6 +6240,37 @@ public class WindowManagerService extends IWindowManager.Stub @EnforcePermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @Override + public void setForcedDisplayDensityRatio(int displayId, float ratio, int userId) { + setForcedDisplayDensityRatio_enforcePermission(); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + setForcedDisplayDensityRatioInternal(displayId, ratio, userId); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void setForcedDisplayDensityRatioInternal( + int displayId, float ratio, int userId) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent != null) { + displayContent.setForcedDensityRatio(ratio, userId); + return; + } + + final DisplayInfo info = mDisplayManagerInternal.getDisplayInfo(displayId); + if (info == null) { + ProtoLog.e(WM_ERROR, "Failed to get information about logical display %d. " + + "Skip setting forced display density.", displayId); + return; + } + mDisplayWindowSettings.setForcedDensityRatio(info, ratio); + } + + @EnforcePermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + @Override public void setConfigurationChangeSettingsForUser( @NonNull List<ConfigurationChangeSetting> settings, int userId) { setConfigurationChangeSettingsForUser_enforcePermission(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 25fdedf32908..0d6aba3fef20 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2925,7 +2925,7 @@ public class DisplayContentTests extends WindowTestsBase { @EnableFlags(FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS) @Test - public void testForcedDensityRatioSetForExternalDisplays_persistDensityScaleFlagEnabled() { + public void testForcedDensityRatioSet_persistDensityScaleFlagEnabled() { final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo); displayInfo.displayId = DEFAULT_DISPLAY + 1; displayInfo.type = Display.TYPE_EXTERNAL; @@ -2943,19 +2943,20 @@ public class DisplayContentTests extends WindowTestsBase { baseYDpi); final int forcedDensity = 640; - - // Verify that forcing the density is honored and the size doesn't change. - displayContent.setForcedDensity(forcedDensity, 0 /* userId */); - verifySizes(displayContent, baseWidth, baseHeight, forcedDensity); + displayContent.setForcedDensityRatio( + (float) forcedDensity / baseDensity, 0 /* userId */); // Verify that density ratio is set correctly. assertEquals((float) forcedDensity / baseDensity, - displayContent.mExternalDisplayForcedDensityRatio, 0.01); + displayContent.mForcedDisplayDensityRatio, 0.01); + // Verify that density is set correctly. + assertEquals(forcedDensity, + displayContent.mBaseDisplayDensity); } @EnableFlags(FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS) @Test - public void testForcedDensityUpdateForExternalDisplays_persistDensityScaleFlagEnabled() { + public void testForcedDensityUpdateWithRatio_persistDensityScaleFlagEnabled() { final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo); displayInfo.displayId = DEFAULT_DISPLAY + 1; displayInfo.type = Display.TYPE_EXTERNAL; @@ -2973,14 +2974,12 @@ public class DisplayContentTests extends WindowTestsBase { baseYDpi); final int forcedDensity = 640; - - // Verify that forcing the density is honored and the size doesn't change. - displayContent.setForcedDensity(forcedDensity, 0 /* userId */); - verifySizes(displayContent, baseWidth, baseHeight, forcedDensity); + displayContent.setForcedDensityRatio( + (float) forcedDensity / baseDensity, 0 /* userId */); // Verify that density ratio is set correctly. - assertEquals((float) 2.0f, - displayContent.mExternalDisplayForcedDensityRatio, 0.001); + assertEquals(2.0f, + displayContent.mForcedDisplayDensityRatio, 0.001); displayContent.mInitialDisplayDensity = 160; diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java index 521d8364a31f..e0db6ee94bed 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java @@ -277,18 +277,24 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @EnableFlags(Flags.FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS) @Test public void testSetForcedDensityRatio() { - mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay.getDisplayInfo(), - 300 /* density */, 0 /* userId */); + DisplayInfo info = new DisplayInfo(mDisplayInfo); + info.logicalDensityDpi = 300; + info.type = Display.TYPE_EXTERNAL; + mSecondaryDisplay = createNewDisplay(info); mDisplayWindowSettings.setForcedDensityRatio(mSecondaryDisplay.getDisplayInfo(), 2.0f /* ratio */); mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay); - assertEquals(mSecondaryDisplay.mInitialDisplayDensity * 2.0f, - mSecondaryDisplay.mBaseDisplayDensity, 0.01); + assertEquals((int) (mSecondaryDisplay.mInitialDisplayDensity * 2.0f), + mSecondaryDisplay.mBaseDisplayDensity); + + mWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), + 0 /* userId */); - mWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), 0 /* userId */); assertEquals(mSecondaryDisplay.mInitialDisplayDensity, mSecondaryDisplay.mBaseDisplayDensity); + assertEquals(mSecondaryDisplay.mForcedDisplayDensityRatio, + 0.0f, 0.001); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index 71e84c0f1821..6425aab03cb4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -100,6 +100,8 @@ import android.provider.Settings; import android.util.ArraySet; import android.util.MergedConfiguration; import android.view.ContentRecordingSession; +import android.view.Display; +import android.view.DisplayInfo; import android.view.IWindow; import android.view.InputChannel; import android.view.InputDevice; @@ -1600,6 +1602,60 @@ public class WindowManagerServiceTests extends WindowTestsBase { }); } + @Test + @EnableFlags(Flags.FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS) + public void setForcedDisplayDensityRatio_forExternalDisplay_setsRatio() { + final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo); + displayInfo.displayId = DEFAULT_DISPLAY + 1; + displayInfo.type = Display.TYPE_EXTERNAL; + displayInfo.logicalDensityDpi = 100; + mDisplayContent = createNewDisplay(displayInfo); + final int currentUserId = ActivityManager.getCurrentUser(); + final float forcedDensityRatio = 2f; + + mWm.setForcedDisplayDensityRatio(displayInfo.displayId, forcedDensityRatio, + currentUserId); + + verify(mDisplayContent).setForcedDensityRatio(forcedDensityRatio, + currentUserId); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS) + public void setForcedDisplayDensityRatio_forInternalDisplay_setsRatio() { + final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo); + displayInfo.displayId = DEFAULT_DISPLAY + 1; + displayInfo.type = Display.TYPE_INTERNAL; + mDisplayContent = createNewDisplay(displayInfo); + final int currentUserId = ActivityManager.getCurrentUser(); + final float forcedDensityRatio = 2f; + + mWm.setForcedDisplayDensityRatio(displayInfo.displayId, forcedDensityRatio, + currentUserId); + + verify(mDisplayContent).setForcedDensityRatio(forcedDensityRatio, + currentUserId); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS) + public void clearForcedDisplayDensityRatio_clearsRatioAndDensity() { + final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo); + displayInfo.displayId = DEFAULT_DISPLAY + 1; + displayInfo.type = Display.TYPE_INTERNAL; + mDisplayContent = createNewDisplay(displayInfo); + final int currentUserId = ActivityManager.getCurrentUser(); + + mWm.clearForcedDisplayDensityForUser(displayInfo.displayId, currentUserId); + + verify(mDisplayContent).setForcedDensityRatio(0.0f, + currentUserId); + + assertEquals(mDisplayContent.mBaseDisplayDensity, + mDisplayContent.getInitialDisplayDensity()); + assertEquals(mDisplayContent.mForcedDisplayDensityRatio, 0.0f, 0.001); + } + /** * Simulates IPC transfer by writing the setting to a parcel and reading it back. * |