diff options
author | 2025-03-24 03:41:47 -0700 | |
---|---|---|
committer | 2025-03-24 03:41:47 -0700 | |
commit | 8818f3b3301cf6464fdd220e9f52dbf5ce1ec2e5 (patch) | |
tree | 927f0fbf94923ec16489f128874cd291595e544c | |
parent | 3539a606ee86dcca203e4be739109c736a77f8cd (diff) | |
parent | fc1a2e086c91c7622ff789c400b6f618037ac71d (diff) |
Merge "Add hidden WM API to set external display density ratio." into main
8 files changed, 203 insertions, 39 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 237d8f96496f..4bf64954a380 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 99988cb55840..deee44dd7f61 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -47,7 +47,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; @@ -433,9 +432,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; /** @@ -3120,6 +3119,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); @@ -3137,18 +3142,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 @@ -3172,15 +3181,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 c23dabcd2a48..f49f8f5245e6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6231,6 +6231,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(), @@ -6255,6 +6259,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 6c321f160caf..b7c325878a78 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -3021,7 +3021,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; @@ -3039,19 +3039,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; @@ -3069,14 +3070,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 449ca867b987..9ab20d15acc8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java @@ -280,18 +280,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 795273d47230..7836ca7d1b4d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -98,6 +98,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; @@ -1594,6 +1596,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. * |