Merge "Fix display settings loss: consider all possible DisplayInfo." into main
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index 8bd8098..27e6e09 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -55,8 +55,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
/**
* Implementation of {@link SettingsProvider} that reads the base settings provided in a display
@@ -152,19 +154,35 @@
/**
* Removes display override settings that are no longer associated with active displays.
- * This is necessary because displays can be dynamically added or removed during
- * the system's lifecycle (e.g., user switch, system server restart).
+ * <p>
+ * This cleanup process is essential due to the dynamic nature of displays, which can
+ * be added or removed during various system events such as user switching or
+ * system server restarts.
*
- * @param root The root window container used to obtain the currently active displays.
+ * @param wms the WindowManagerService instance for retrieving all possible {@link DisplayInfo}
+ * for the given logical display.
+ * @param root the root window container used to obtain the currently active displays.
*/
- void removeStaleDisplaySettings(@NonNull RootWindowContainer root) {
+ void removeStaleDisplaySettingsLocked(@NonNull WindowManagerService wms,
+ @NonNull RootWindowContainer root) {
if (!Flags.perUserDisplayWindowSettings()) {
return;
}
final Set<String> displayIdentifiers = new ArraySet<>();
+ final Consumer<DisplayInfo> addDisplayIdentifier =
+ displayInfo -> displayIdentifiers.add(mOverrideSettings.getIdentifier(displayInfo));
root.forAllDisplays(dc -> {
- final String identifier = mOverrideSettings.getIdentifier(dc.getDisplayInfo());
- displayIdentifiers.add(identifier);
+ // Begin with the current display's information. Note that the display layout of the
+ // current device state might not include this display (e.g., external or virtual
+ // displays), resulting in empty possible display info.
+ addDisplayIdentifier.accept(dc.getDisplayInfo());
+
+ // Then, add all possible display information for this display if available.
+ final List<DisplayInfo> displayInfos = wms.getPossibleDisplayInfoLocked(dc.mDisplayId);
+ final int size = displayInfos.size();
+ for (int i = 0; i < size; i++) {
+ addDisplayIdentifier.accept(displayInfos.get(i));
+ }
});
mOverrideSettings.removeStaleDisplaySettings(displayIdentifiers);
}
diff --git a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
index e3a2065..6e87977 100644
--- a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
+++ b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
@@ -57,7 +57,7 @@
* Returns, for the given displayId, a list of unique display infos. List contains each
* supported device state.
* <p>List contents are guaranteed to be unique, but returned as a list rather than a set to
- * minimize copies needed to make an iteraable data structure.
+ * minimize copies needed to make an iterable data structure.
*/
public List<DisplayInfo> getPossibleDisplayInfos(int displayId) {
// Update display infos before returning, since any cached values would have been removed
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9884df9..13453a6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3749,7 +3749,7 @@
}
mCurrentUserId = newUserId;
mDisplayWindowSettingsProvider.setOverrideSettingsForUser(newUserId);
- mDisplayWindowSettingsProvider.removeStaleDisplaySettings(mRoot);
+ mDisplayWindowSettingsProvider.removeStaleDisplaySettingsLocked(this, mRoot);
mPolicy.setCurrentUserLw(newUserId);
mKeyguardDisableHandler.setCurrentUser(newUserId);
@@ -5490,7 +5490,7 @@
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
// Per-user display settings may leave outdated settings after user switches, especially
// during reboots starting with the default user without setCurrentUser called.
- mDisplayWindowSettingsProvider.removeStaleDisplaySettings(mRoot);
+ mDisplayWindowSettingsProvider.removeStaleDisplaySettingsLocked(this, mRoot);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 3fcf304..2e0d4d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -24,12 +24,15 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.testng.Assert.assertFalse;
import android.annotation.Nullable;
@@ -58,6 +61,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -352,20 +356,58 @@
}
@Test
- public void testRemovesStaleDisplaySettings() {
+ public void testRemovesStaleDisplaySettings_defaultDisplay_removesStaleDisplaySettings() {
assumeTrue(com.android.window.flags.Flags.perUserDisplayWindowSettings());
- final DisplayWindowSettingsProvider provider =
- new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
- mOverrideSettingsStorage);
- final DisplayInfo displayInfo = mSecondaryDisplay.getDisplayInfo();
- updateOverrideSettings(provider, displayInfo, settings -> settings.mForcedDensity = 356);
+ // Write density setting for second display then remove it.
+ final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
+ final DisplayInfo secDisplayInfo = mSecondaryDisplay.getDisplayInfo();
+ updateOverrideSettings(provider, secDisplayInfo, setting -> setting.mForcedDensity = 356);
mRootWindowContainer.removeChild(mSecondaryDisplay);
- provider.removeStaleDisplaySettings(mRootWindowContainer);
+ // Write density setting for inner and outer default display.
+ final DisplayInfo innerDisplayInfo = mPrimaryDisplay.getDisplayInfo();
+ final DisplayInfo outerDisplayInfo = new DisplayInfo(secDisplayInfo);
+ outerDisplayInfo.displayId = mPrimaryDisplay.mDisplayId;
+ outerDisplayInfo.uniqueId = "TEST_OUTER_DISPLAY_" + System.currentTimeMillis();
+ updateOverrideSettings(provider, innerDisplayInfo, setting -> setting.mForcedDensity = 490);
+ updateOverrideSettings(provider, outerDisplayInfo, setting -> setting.mForcedDensity = 420);
+ final List<DisplayInfo> possibleDisplayInfos = List.of(innerDisplayInfo, outerDisplayInfo);
+ doReturn(possibleDisplayInfos)
+ .when(mWm).getPossibleDisplayInfoLocked(eq(innerDisplayInfo.displayId));
+
+ provider.removeStaleDisplaySettingsLocked(mWm, mRootWindowContainer);
assertThat(mOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
- assertThat(provider.getOverrideSettingsSize()).isEqualTo(0);
+ assertThat(provider.getOverrideSettingsSize()).isEqualTo(2);
+ assertThat(provider.getOverrideSettings(innerDisplayInfo).mForcedDensity).isEqualTo(490);
+ assertThat(provider.getOverrideSettings(outerDisplayInfo).mForcedDensity).isEqualTo(420);
+ }
+
+ @Test
+ public void testRemovesStaleDisplaySettings_displayNotInLayout_keepsDisplaySettings() {
+ assumeTrue(com.android.window.flags.Flags.perUserDisplayWindowSettings());
+
+ // Write density setting for primary display.
+ final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
+ final DisplayInfo primDisplayInfo = mPrimaryDisplay.getDisplayInfo();
+ updateOverrideSettings(provider, primDisplayInfo, setting -> setting.mForcedDensity = 420);
+
+ // Add a virtual display and write density setting for it.
+ final DisplayInfo virtDisplayInfo = new DisplayInfo(primDisplayInfo);
+ virtDisplayInfo.uniqueId = "TEST_VIRTUAL_DISPLAY_" + System.currentTimeMillis();
+ createNewDisplay(virtDisplayInfo);
+ waitUntilHandlersIdle(); // Wait until unfrozen after a display is added.
+ updateOverrideSettings(provider, virtDisplayInfo, setting -> setting.mForcedDensity = 490);
+
+ provider.removeStaleDisplaySettingsLocked(mWm, mRootWindowContainer);
+
+ assertThat(mOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
+ assertThat(provider.getOverrideSettingsSize()).isEqualTo(2);
+ assertThat(provider.getOverrideSettings(primDisplayInfo).mForcedDensity).isEqualTo(420);
+ assertThat(provider.getOverrideSettings(virtDisplayInfo).mForcedDensity).isEqualTo(490);
}
/**