Loading core/java/android/provider/Settings.java +5 −4 Original line number Diff line number Diff line Loading @@ -9797,12 +9797,13 @@ public final class Settings { "use_blast_adapter_sv"; /** * If {@code true}, vendor provided window manager display settings will be ignored. * (0 = false, 1 = true) * Path to the WindowManager display settings file. If unset, the default file path will * be used. * * @hide */ public static final String DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS = "ignore_vendor_display_settings"; public static final String DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH = "wm_display_settings_path"; /** * Whether user has enabled development settings. Loading packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -230,7 +230,7 @@ public class SettingsBackupTest { Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH, Settings.Global.DEVICE_DEMO_MODE, Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS, Settings.Global.BATTERY_SAVER_CONSTANTS, Loading services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java +121 −115 Original line number Diff line number Diff line Loading @@ -16,9 +16,9 @@ package com.android.server.wm; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading Loading @@ -64,7 +64,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider { ? "DisplayWindowSettingsProvider" : TAG_WM; private static final String DATA_DISPLAY_SETTINGS_FILE_PATH = "system/display_settings.xml"; private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/display_settings.xml"; private static final String VENDOR_DISPLAY_SETTINGS_FILE_PATH = "etc/display_settings.xml"; private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays"; private static final int IDENTIFIER_UNIQUE_ID = 0; Loading @@ -86,34 +86,8 @@ class DisplayWindowSettingsProvider implements SettingsProvider { void finishWrite(OutputStream os, boolean success); } private final ReadableSettingsStorage mVendorSettingsStorage; /** * The preferred type of a display identifier to use when storing and retrieving entries from * the base (vendor) settings file. * * @see #getIdentifier(DisplayInfo, int) */ @DisplayIdentifierType private int mVendorIdentifierType; private final Map<String, SettingsEntry> mVendorSettings = new HashMap<>(); private final WritableSettingsStorage mOverrideSettingsStorage; /** * The preferred type of a display identifier to use when storing and retrieving entries from * the data (override) settings file. * * @see #getIdentifier(DisplayInfo, int) */ @DisplayIdentifierType private int mOverrideIdentifierType; private final Map<String, SettingsEntry> mOverrideSettings = new HashMap<>(); /** * Enables or disables settings provided from the vendor settings storage. * * @see #setVendorSettingsIgnored(boolean) */ private boolean mIgnoreVendorSettings = true; private ReadableSettings mBaseSettings; private final WritableSettings mOverrideSettings; DisplayWindowSettingsProvider() { this(new AtomicFileStorage(getVendorSettingsFile()), Loading @@ -121,43 +95,48 @@ class DisplayWindowSettingsProvider implements SettingsProvider { } @VisibleForTesting DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage vendorSettingsStorage, DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage baseSettingsStorage, @NonNull WritableSettingsStorage overrideSettingsStorage) { mVendorSettingsStorage = vendorSettingsStorage; mOverrideSettingsStorage = overrideSettingsStorage; readSettings(); mBaseSettings = new ReadableSettings(baseSettingsStorage); mOverrideSettings = new WritableSettings(overrideSettingsStorage); } /** * Enables or disables settings provided from the vendor settings storage. If {@code true}, the * vendor settings will be ignored and only the override settings will be returned from * {@link #getSettings(DisplayInfo)}. If {@code false}, settings returned from * {@link #getSettings(DisplayInfo)} will be a merged result of the vendor settings and the * override settings. * Overrides the path for the file that should be used to read base settings. If {@code null} is * passed the default base settings file path will be used. * * @see #VENDOR_DISPLAY_SETTINGS_FILE_PATH */ void setVendorSettingsIgnored(boolean ignored) { mIgnoreVendorSettings = ignored; void setBaseSettingsFilePath(@Nullable String path) { AtomicFile settingsFile; if (path != null) { settingsFile = new AtomicFile(new File(path), WM_DISPLAY_COMMIT_TAG); } else { settingsFile = getVendorSettingsFile(); } setBaseSettingsStorage(new AtomicFileStorage(settingsFile)); } /** * Returns whether or not the vendor settings are being ignored. * Overrides the storage that should be used to read base settings. * * @see #setVendorSettingsIgnored(boolean) * @see #setBaseSettingsFilePath(String) */ @VisibleForTesting boolean getVendorSettingsIgnored() { return mIgnoreVendorSettings; void setBaseSettingsStorage(@NonNull ReadableSettingsStorage baseSettingsStorage) { mBaseSettings = new ReadableSettings(baseSettingsStorage); } @Override @NonNull public SettingsEntry getSettings(@NonNull DisplayInfo info) { SettingsEntry vendorSettings = getVendorSettingsEntry(info); SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info); if (vendorSettings == null) { SettingsEntry baseSettings = mBaseSettings.getSettingsEntry(info); SettingsEntry overrideSettings = mOverrideSettings.getOrCreateSettingsEntry(info); if (baseSettings == null) { return new SettingsEntry(overrideSettings); } else { SettingsEntry mergedSettings = new SettingsEntry(vendorSettings); SettingsEntry mergedSettings = new SettingsEntry(baseSettings); mergedSettings.updateFrom(overrideSettings); return mergedSettings; } Loading @@ -166,99 +145,126 @@ class DisplayWindowSettingsProvider implements SettingsProvider { @Override @NonNull public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) { return new SettingsEntry(getOrCreateOverrideSettingsEntry(info)); return new SettingsEntry(mOverrideSettings.getOrCreateSettingsEntry(info)); } @Override public void updateOverrideSettings(@NonNull DisplayInfo info, @NonNull SettingsEntry overrides) { final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info); boolean changed = overrideSettings.setTo(overrides); if (changed) { writeOverrideSettings(); } mOverrideSettings.updateSettingsEntry(info, overrides); } @Nullable private SettingsEntry getVendorSettingsEntry(DisplayInfo info) { if (mIgnoreVendorSettings) { return null; /** * Class that allows reading {@link SettingsEntry entries} from a * {@link ReadableSettingsStorage}. */ private static class ReadableSettings { /** * The preferred type of a display identifier to use when storing and retrieving entries * from the settings entries. * * @see #getIdentifier(DisplayInfo) */ @DisplayIdentifierType protected int mIdentifierType; protected final Map<String, SettingsEntry> mSettings = new HashMap<>(); ReadableSettings(ReadableSettingsStorage settingsStorage) { loadSettings(settingsStorage); } final String identifier = getIdentifier(info, mVendorIdentifierType); @Nullable final SettingsEntry getSettingsEntry(DisplayInfo info) { final String identifier = getIdentifier(info); SettingsEntry settings; // Try to get corresponding settings using preferred identifier for the current config. if ((settings = mVendorSettings.get(identifier)) != null) { if ((settings = mSettings.get(identifier)) != null) { return settings; } // Else, fall back to the display name. if ((settings = mVendorSettings.get(info.name)) != null) { if ((settings = mSettings.get(info.name)) != null) { // Found an entry stored with old identifier. mVendorSettings.remove(info.name); mVendorSettings.put(identifier, settings); mSettings.remove(info.name); mSettings.put(identifier, settings); return settings; } return null; } /** Gets the identifier of choice for the current config. */ protected final String getIdentifier(DisplayInfo displayInfo) { if (mIdentifierType == IDENTIFIER_PORT && displayInfo.address != null) { // Config suggests using port as identifier for physical displays. if (displayInfo.address instanceof DisplayAddress.Physical) { return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort(); } } return displayInfo.uniqueId; } private void loadSettings(ReadableSettingsStorage settingsStorage) { FileData fileData = readSettings(settingsStorage); if (fileData != null) { mIdentifierType = fileData.mIdentifierType; mSettings.putAll(fileData.mSettings); } } } /** * Class that allows reading {@link SettingsEntry entries} from, and writing entries to, a * {@link WritableSettingsStorage}. */ private static final class WritableSettings extends ReadableSettings { private final WritableSettingsStorage mSettingsStorage; WritableSettings(WritableSettingsStorage settingsStorage) { super(settingsStorage); mSettingsStorage = settingsStorage; } @NonNull private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) { final String identifier = getIdentifier(info, mOverrideIdentifierType); SettingsEntry getOrCreateSettingsEntry(DisplayInfo info) { final String identifier = getIdentifier(info); SettingsEntry settings; // Try to get corresponding settings using preferred identifier for the current config. if ((settings = mOverrideSettings.get(identifier)) != null) { if ((settings = mSettings.get(identifier)) != null) { return settings; } // Else, fall back to the display name. if ((settings = mOverrideSettings.get(info.name)) != null) { if ((settings = mSettings.get(info.name)) != null) { // Found an entry stored with old identifier. mOverrideSettings.remove(info.name); mOverrideSettings.put(identifier, settings); writeOverrideSettings(); mSettings.remove(info.name); mSettings.put(identifier, settings); writeSettings(); return settings; } settings = new SettingsEntry(); mOverrideSettings.put(identifier, settings); mSettings.put(identifier, settings); return settings; } private void readSettings() { FileData vendorFileData = readSettings(mVendorSettingsStorage); if (vendorFileData != null) { mVendorIdentifierType = vendorFileData.mIdentifierType; mVendorSettings.putAll(vendorFileData.mSettings); } FileData overrideFileData = readSettings(mOverrideSettingsStorage); if (overrideFileData != null) { mOverrideIdentifierType = overrideFileData.mIdentifierType; mOverrideSettings.putAll(overrideFileData.mSettings); void updateSettingsEntry(DisplayInfo info, SettingsEntry settings) { final SettingsEntry overrideSettings = getOrCreateSettingsEntry(info); final boolean changed = overrideSettings.setTo(settings); if (changed) { writeSettings(); } } private void writeOverrideSettings() { private void writeSettings() { FileData fileData = new FileData(); fileData.mIdentifierType = mOverrideIdentifierType; fileData.mSettings.putAll(mOverrideSettings); writeSettings(mOverrideSettingsStorage, fileData); fileData.mIdentifierType = mIdentifierType; fileData.mSettings.putAll(mSettings); DisplayWindowSettingsProvider.writeSettings(mSettingsStorage, fileData); } /** Gets the identifier of choice for the current config. */ private static String getIdentifier(DisplayInfo displayInfo, @DisplayIdentifierType int type) { if (type == IDENTIFIER_PORT && displayInfo.address != null) { // Config suggests using port as identifier for physical displays. if (displayInfo.address instanceof DisplayAddress.Physical) { return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort(); } } return displayInfo.uniqueId; } @NonNull private static AtomicFile getVendorSettingsFile() { final File vendorFile = new File(Environment.getVendorDirectory(), VENDOR_DISPLAY_SETTINGS_PATH); VENDOR_DISPLAY_SETTINGS_FILE_PATH); return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG); } Loading services/core/java/com/android/server/wm/WindowManagerService.java +15 −13 Original line number Diff line number Diff line Loading @@ -44,8 +44,8 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS; import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR; import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; Loading Loading @@ -796,8 +796,8 @@ public class WindowManagerService extends IWindowManager.Stub DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM); private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor( DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR); private final Uri mIgnoreVendorDisplaySettingsUri = Settings.Global.getUriFor( DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS); private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor( DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); public SettingsObserver() { super(new Handler()); Loading @@ -822,7 +822,7 @@ public class WindowManagerService extends IWindowManager.Stub UserHandle.USER_ALL); resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this, UserHandle.USER_ALL); resolver.registerContentObserver(mIgnoreVendorDisplaySettingsUri, false, this, resolver.registerContentObserver(mDisplaySettingsPathUri, false, this, UserHandle.USER_ALL); } Loading Loading @@ -867,8 +867,8 @@ public class WindowManagerService extends IWindowManager.Stub return; } if (mIgnoreVendorDisplaySettingsUri.equals(uri)) { updateIgnoreVendorDisplaySettings(); if (mDisplaySettingsPathUri.equals(uri)) { updateDisplaySettingsLocation(); return; } Loading Loading @@ -962,12 +962,12 @@ public class WindowManagerService extends IWindowManager.Stub mAtmService.mSizeCompatFreeform = sizeCompatFreeform; } void updateIgnoreVendorDisplaySettings() { void updateDisplaySettingsLocation() { final ContentResolver resolver = mContext.getContentResolver(); final boolean ignoreVendorSettings = Settings.Global.getInt(resolver, DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0; final String filePath = Settings.Global.getString(resolver, DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); synchronized (mGlobalLock) { mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorSettings); mDisplayWindowSettingsProvider.setBaseSettingsFilePath(filePath); mRoot.forAllDisplays(display -> { mDisplayWindowSettings.applySettingsToDisplayLocked(display); display.reconfigureDisplayLocked(); Loading Loading @@ -1330,10 +1330,12 @@ public class WindowManagerService extends IWindowManager.Stub mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0; final boolean ignoreVendorDisplaySettings = Settings.Global.getInt(resolver, DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0; final String displaySettingsPath = Settings.Global.getString(resolver, DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider(); mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorDisplaySettings); if (displaySettingsPath != null) { mDisplayWindowSettingsProvider.setBaseSettingsFilePath(displaySettingsPath); } mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider); IntentFilter filter = new IntentFilter(); Loading services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java +72 −7 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; Loading @@ -28,7 +30,6 @@ import static org.junit.Assert.assertTrue; import android.annotation.Nullable; import android.platform.test.annotations.Presubmit; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.Xml; import android.view.Display; import android.view.DisplayAddress; Loading Loading @@ -69,7 +70,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir(); private TestStorage mBaseSettingsStorage; private TestStorage mDefaultVendorSettingsStorage; private TestStorage mSecondaryVendorSettingsStorage; private TestStorage mOverrideSettingsStorage; private DisplayContent mPrimaryDisplay; Loading @@ -79,7 +81,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { public void setUp() throws Exception { deleteRecursively(TEST_FOLDER); mBaseSettingsStorage = new TestStorage(); mDefaultVendorSettingsStorage = new TestStorage(); mSecondaryVendorSettingsStorage = new TestStorage(); mOverrideSettingsStorage = new TestStorage(); mPrimaryDisplay = mWm.getDefaultDisplayContentLocked(); Loading Loading @@ -122,7 +125,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { // Update settings with new value, should trigger write to injector. DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider( mBaseSettingsStorage, mOverrideSettingsStorage); mDefaultVendorSettingsStorage, mOverrideSettingsStorage); SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo); overrideSettings.mForcedDensity = 200; provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings); Loading Loading @@ -161,13 +164,56 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings); } @Test public void testReadingDisplaySettingsFromStorage_secondayVendorDisplaySettingsLocation() { final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId; prepareSecondaryDisplaySettings(displayIdentifier); final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage, mOverrideSettingsStorage); // Expected settings should be empty because the default is to read from the primary vendor // settings location. SettingsEntry expectedSettings = new SettingsEntry(); assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); // Now switch to secondary vendor settings and assert proper settings. provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage); expectedSettings.mWindowingMode = WINDOWING_MODE_FULLSCREEN; assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); // Switch back to primary and assert settings are empty again. provider.setBaseSettingsStorage(mDefaultVendorSettingsStorage); expectedSettings.mWindowingMode = WINDOWING_MODE_UNDEFINED; assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); } @Test public void testReadingDisplaySettingsFromStorage_overrideSettingsTakePrecedenceOverVendor() { final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId; prepareOverrideDisplaySettings(displayIdentifier); prepareSecondaryDisplaySettings(displayIdentifier); final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage, mOverrideSettingsStorage); provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage); // The windowing mode should be set to WINDOWING_MODE_PINNED because the override settings // take precedence over the vendor provided settings. SettingsEntry expectedSettings = new SettingsEntry(); expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED; assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); } @Test public void testWritingDisplaySettingsToStorage() throws Exception { final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo(); // Write some settings to storage. DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider( mBaseSettingsStorage, mOverrideSettingsStorage); mDefaultVendorSettingsStorage, mOverrideSettingsStorage); SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo); overrideSettings.mShouldShowSystemDecors = true; overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL; Loading Loading @@ -195,7 +241,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { // Write some settings to storage. DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider( mBaseSettingsStorage, mOverrideSettingsStorage); mDefaultVendorSettingsStorage, mOverrideSettingsStorage); SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo); overrideSettings.mShouldShowSystemDecors = true; overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL; Loading Loading @@ -236,10 +282,29 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { mOverrideSettingsStorage.setReadStream(is); } /** * Prepares display settings and stores in {@link #mSecondaryVendorSettingsStorage}. Uses * provided display identifier and stores windowingMode=WINDOWING_MODE_FULLSCREEN. */ private void prepareSecondaryDisplaySettings(String displayIdentifier) { String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + "<display-settings>\n"; if (displayIdentifier != null) { contents += " <display\n" + " name=\"" + displayIdentifier + "\"\n" + " windowingMode=\"" + WINDOWING_MODE_FULLSCREEN + "\"/>\n"; } contents += "</display-settings>\n"; final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)); mSecondaryVendorSettingsStorage.setReadStream(is); } private void readAndAssertExpectedSettings(DisplayContent displayContent, SettingsEntry expectedSettings) { final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(mBaseSettingsStorage, mOverrideSettingsStorage); new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage, mOverrideSettingsStorage); assertEquals(expectedSettings, provider.getSettings(displayContent.getDisplayInfo())); } Loading Loading
core/java/android/provider/Settings.java +5 −4 Original line number Diff line number Diff line Loading @@ -9797,12 +9797,13 @@ public final class Settings { "use_blast_adapter_sv"; /** * If {@code true}, vendor provided window manager display settings will be ignored. * (0 = false, 1 = true) * Path to the WindowManager display settings file. If unset, the default file path will * be used. * * @hide */ public static final String DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS = "ignore_vendor_display_settings"; public static final String DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH = "wm_display_settings_path"; /** * Whether user has enabled development settings. Loading
packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -230,7 +230,7 @@ public class SettingsBackupTest { Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH, Settings.Global.DEVICE_DEMO_MODE, Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS, Settings.Global.BATTERY_SAVER_CONSTANTS, Loading
services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java +121 −115 Original line number Diff line number Diff line Loading @@ -16,9 +16,9 @@ package com.android.server.wm; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading Loading @@ -64,7 +64,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider { ? "DisplayWindowSettingsProvider" : TAG_WM; private static final String DATA_DISPLAY_SETTINGS_FILE_PATH = "system/display_settings.xml"; private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/display_settings.xml"; private static final String VENDOR_DISPLAY_SETTINGS_FILE_PATH = "etc/display_settings.xml"; private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays"; private static final int IDENTIFIER_UNIQUE_ID = 0; Loading @@ -86,34 +86,8 @@ class DisplayWindowSettingsProvider implements SettingsProvider { void finishWrite(OutputStream os, boolean success); } private final ReadableSettingsStorage mVendorSettingsStorage; /** * The preferred type of a display identifier to use when storing and retrieving entries from * the base (vendor) settings file. * * @see #getIdentifier(DisplayInfo, int) */ @DisplayIdentifierType private int mVendorIdentifierType; private final Map<String, SettingsEntry> mVendorSettings = new HashMap<>(); private final WritableSettingsStorage mOverrideSettingsStorage; /** * The preferred type of a display identifier to use when storing and retrieving entries from * the data (override) settings file. * * @see #getIdentifier(DisplayInfo, int) */ @DisplayIdentifierType private int mOverrideIdentifierType; private final Map<String, SettingsEntry> mOverrideSettings = new HashMap<>(); /** * Enables or disables settings provided from the vendor settings storage. * * @see #setVendorSettingsIgnored(boolean) */ private boolean mIgnoreVendorSettings = true; private ReadableSettings mBaseSettings; private final WritableSettings mOverrideSettings; DisplayWindowSettingsProvider() { this(new AtomicFileStorage(getVendorSettingsFile()), Loading @@ -121,43 +95,48 @@ class DisplayWindowSettingsProvider implements SettingsProvider { } @VisibleForTesting DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage vendorSettingsStorage, DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage baseSettingsStorage, @NonNull WritableSettingsStorage overrideSettingsStorage) { mVendorSettingsStorage = vendorSettingsStorage; mOverrideSettingsStorage = overrideSettingsStorage; readSettings(); mBaseSettings = new ReadableSettings(baseSettingsStorage); mOverrideSettings = new WritableSettings(overrideSettingsStorage); } /** * Enables or disables settings provided from the vendor settings storage. If {@code true}, the * vendor settings will be ignored and only the override settings will be returned from * {@link #getSettings(DisplayInfo)}. If {@code false}, settings returned from * {@link #getSettings(DisplayInfo)} will be a merged result of the vendor settings and the * override settings. * Overrides the path for the file that should be used to read base settings. If {@code null} is * passed the default base settings file path will be used. * * @see #VENDOR_DISPLAY_SETTINGS_FILE_PATH */ void setVendorSettingsIgnored(boolean ignored) { mIgnoreVendorSettings = ignored; void setBaseSettingsFilePath(@Nullable String path) { AtomicFile settingsFile; if (path != null) { settingsFile = new AtomicFile(new File(path), WM_DISPLAY_COMMIT_TAG); } else { settingsFile = getVendorSettingsFile(); } setBaseSettingsStorage(new AtomicFileStorage(settingsFile)); } /** * Returns whether or not the vendor settings are being ignored. * Overrides the storage that should be used to read base settings. * * @see #setVendorSettingsIgnored(boolean) * @see #setBaseSettingsFilePath(String) */ @VisibleForTesting boolean getVendorSettingsIgnored() { return mIgnoreVendorSettings; void setBaseSettingsStorage(@NonNull ReadableSettingsStorage baseSettingsStorage) { mBaseSettings = new ReadableSettings(baseSettingsStorage); } @Override @NonNull public SettingsEntry getSettings(@NonNull DisplayInfo info) { SettingsEntry vendorSettings = getVendorSettingsEntry(info); SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info); if (vendorSettings == null) { SettingsEntry baseSettings = mBaseSettings.getSettingsEntry(info); SettingsEntry overrideSettings = mOverrideSettings.getOrCreateSettingsEntry(info); if (baseSettings == null) { return new SettingsEntry(overrideSettings); } else { SettingsEntry mergedSettings = new SettingsEntry(vendorSettings); SettingsEntry mergedSettings = new SettingsEntry(baseSettings); mergedSettings.updateFrom(overrideSettings); return mergedSettings; } Loading @@ -166,99 +145,126 @@ class DisplayWindowSettingsProvider implements SettingsProvider { @Override @NonNull public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) { return new SettingsEntry(getOrCreateOverrideSettingsEntry(info)); return new SettingsEntry(mOverrideSettings.getOrCreateSettingsEntry(info)); } @Override public void updateOverrideSettings(@NonNull DisplayInfo info, @NonNull SettingsEntry overrides) { final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info); boolean changed = overrideSettings.setTo(overrides); if (changed) { writeOverrideSettings(); } mOverrideSettings.updateSettingsEntry(info, overrides); } @Nullable private SettingsEntry getVendorSettingsEntry(DisplayInfo info) { if (mIgnoreVendorSettings) { return null; /** * Class that allows reading {@link SettingsEntry entries} from a * {@link ReadableSettingsStorage}. */ private static class ReadableSettings { /** * The preferred type of a display identifier to use when storing and retrieving entries * from the settings entries. * * @see #getIdentifier(DisplayInfo) */ @DisplayIdentifierType protected int mIdentifierType; protected final Map<String, SettingsEntry> mSettings = new HashMap<>(); ReadableSettings(ReadableSettingsStorage settingsStorage) { loadSettings(settingsStorage); } final String identifier = getIdentifier(info, mVendorIdentifierType); @Nullable final SettingsEntry getSettingsEntry(DisplayInfo info) { final String identifier = getIdentifier(info); SettingsEntry settings; // Try to get corresponding settings using preferred identifier for the current config. if ((settings = mVendorSettings.get(identifier)) != null) { if ((settings = mSettings.get(identifier)) != null) { return settings; } // Else, fall back to the display name. if ((settings = mVendorSettings.get(info.name)) != null) { if ((settings = mSettings.get(info.name)) != null) { // Found an entry stored with old identifier. mVendorSettings.remove(info.name); mVendorSettings.put(identifier, settings); mSettings.remove(info.name); mSettings.put(identifier, settings); return settings; } return null; } /** Gets the identifier of choice for the current config. */ protected final String getIdentifier(DisplayInfo displayInfo) { if (mIdentifierType == IDENTIFIER_PORT && displayInfo.address != null) { // Config suggests using port as identifier for physical displays. if (displayInfo.address instanceof DisplayAddress.Physical) { return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort(); } } return displayInfo.uniqueId; } private void loadSettings(ReadableSettingsStorage settingsStorage) { FileData fileData = readSettings(settingsStorage); if (fileData != null) { mIdentifierType = fileData.mIdentifierType; mSettings.putAll(fileData.mSettings); } } } /** * Class that allows reading {@link SettingsEntry entries} from, and writing entries to, a * {@link WritableSettingsStorage}. */ private static final class WritableSettings extends ReadableSettings { private final WritableSettingsStorage mSettingsStorage; WritableSettings(WritableSettingsStorage settingsStorage) { super(settingsStorage); mSettingsStorage = settingsStorage; } @NonNull private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) { final String identifier = getIdentifier(info, mOverrideIdentifierType); SettingsEntry getOrCreateSettingsEntry(DisplayInfo info) { final String identifier = getIdentifier(info); SettingsEntry settings; // Try to get corresponding settings using preferred identifier for the current config. if ((settings = mOverrideSettings.get(identifier)) != null) { if ((settings = mSettings.get(identifier)) != null) { return settings; } // Else, fall back to the display name. if ((settings = mOverrideSettings.get(info.name)) != null) { if ((settings = mSettings.get(info.name)) != null) { // Found an entry stored with old identifier. mOverrideSettings.remove(info.name); mOverrideSettings.put(identifier, settings); writeOverrideSettings(); mSettings.remove(info.name); mSettings.put(identifier, settings); writeSettings(); return settings; } settings = new SettingsEntry(); mOverrideSettings.put(identifier, settings); mSettings.put(identifier, settings); return settings; } private void readSettings() { FileData vendorFileData = readSettings(mVendorSettingsStorage); if (vendorFileData != null) { mVendorIdentifierType = vendorFileData.mIdentifierType; mVendorSettings.putAll(vendorFileData.mSettings); } FileData overrideFileData = readSettings(mOverrideSettingsStorage); if (overrideFileData != null) { mOverrideIdentifierType = overrideFileData.mIdentifierType; mOverrideSettings.putAll(overrideFileData.mSettings); void updateSettingsEntry(DisplayInfo info, SettingsEntry settings) { final SettingsEntry overrideSettings = getOrCreateSettingsEntry(info); final boolean changed = overrideSettings.setTo(settings); if (changed) { writeSettings(); } } private void writeOverrideSettings() { private void writeSettings() { FileData fileData = new FileData(); fileData.mIdentifierType = mOverrideIdentifierType; fileData.mSettings.putAll(mOverrideSettings); writeSettings(mOverrideSettingsStorage, fileData); fileData.mIdentifierType = mIdentifierType; fileData.mSettings.putAll(mSettings); DisplayWindowSettingsProvider.writeSettings(mSettingsStorage, fileData); } /** Gets the identifier of choice for the current config. */ private static String getIdentifier(DisplayInfo displayInfo, @DisplayIdentifierType int type) { if (type == IDENTIFIER_PORT && displayInfo.address != null) { // Config suggests using port as identifier for physical displays. if (displayInfo.address instanceof DisplayAddress.Physical) { return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort(); } } return displayInfo.uniqueId; } @NonNull private static AtomicFile getVendorSettingsFile() { final File vendorFile = new File(Environment.getVendorDirectory(), VENDOR_DISPLAY_SETTINGS_PATH); VENDOR_DISPLAY_SETTINGS_FILE_PATH); return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG); } Loading
services/core/java/com/android/server/wm/WindowManagerService.java +15 −13 Original line number Diff line number Diff line Loading @@ -44,8 +44,8 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS; import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR; import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; Loading Loading @@ -796,8 +796,8 @@ public class WindowManagerService extends IWindowManager.Stub DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM); private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor( DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR); private final Uri mIgnoreVendorDisplaySettingsUri = Settings.Global.getUriFor( DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS); private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor( DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); public SettingsObserver() { super(new Handler()); Loading @@ -822,7 +822,7 @@ public class WindowManagerService extends IWindowManager.Stub UserHandle.USER_ALL); resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this, UserHandle.USER_ALL); resolver.registerContentObserver(mIgnoreVendorDisplaySettingsUri, false, this, resolver.registerContentObserver(mDisplaySettingsPathUri, false, this, UserHandle.USER_ALL); } Loading Loading @@ -867,8 +867,8 @@ public class WindowManagerService extends IWindowManager.Stub return; } if (mIgnoreVendorDisplaySettingsUri.equals(uri)) { updateIgnoreVendorDisplaySettings(); if (mDisplaySettingsPathUri.equals(uri)) { updateDisplaySettingsLocation(); return; } Loading Loading @@ -962,12 +962,12 @@ public class WindowManagerService extends IWindowManager.Stub mAtmService.mSizeCompatFreeform = sizeCompatFreeform; } void updateIgnoreVendorDisplaySettings() { void updateDisplaySettingsLocation() { final ContentResolver resolver = mContext.getContentResolver(); final boolean ignoreVendorSettings = Settings.Global.getInt(resolver, DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0; final String filePath = Settings.Global.getString(resolver, DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); synchronized (mGlobalLock) { mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorSettings); mDisplayWindowSettingsProvider.setBaseSettingsFilePath(filePath); mRoot.forAllDisplays(display -> { mDisplayWindowSettings.applySettingsToDisplayLocked(display); display.reconfigureDisplayLocked(); Loading Loading @@ -1330,10 +1330,12 @@ public class WindowManagerService extends IWindowManager.Stub mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0; final boolean ignoreVendorDisplaySettings = Settings.Global.getInt(resolver, DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0; final String displaySettingsPath = Settings.Global.getString(resolver, DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider(); mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorDisplaySettings); if (displaySettingsPath != null) { mDisplayWindowSettingsProvider.setBaseSettingsFilePath(displaySettingsPath); } mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider); IntentFilter filter = new IntentFilter(); Loading
services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java +72 −7 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; Loading @@ -28,7 +30,6 @@ import static org.junit.Assert.assertTrue; import android.annotation.Nullable; import android.platform.test.annotations.Presubmit; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.Xml; import android.view.Display; import android.view.DisplayAddress; Loading Loading @@ -69,7 +70,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir(); private TestStorage mBaseSettingsStorage; private TestStorage mDefaultVendorSettingsStorage; private TestStorage mSecondaryVendorSettingsStorage; private TestStorage mOverrideSettingsStorage; private DisplayContent mPrimaryDisplay; Loading @@ -79,7 +81,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { public void setUp() throws Exception { deleteRecursively(TEST_FOLDER); mBaseSettingsStorage = new TestStorage(); mDefaultVendorSettingsStorage = new TestStorage(); mSecondaryVendorSettingsStorage = new TestStorage(); mOverrideSettingsStorage = new TestStorage(); mPrimaryDisplay = mWm.getDefaultDisplayContentLocked(); Loading Loading @@ -122,7 +125,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { // Update settings with new value, should trigger write to injector. DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider( mBaseSettingsStorage, mOverrideSettingsStorage); mDefaultVendorSettingsStorage, mOverrideSettingsStorage); SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo); overrideSettings.mForcedDensity = 200; provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings); Loading Loading @@ -161,13 +164,56 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings); } @Test public void testReadingDisplaySettingsFromStorage_secondayVendorDisplaySettingsLocation() { final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId; prepareSecondaryDisplaySettings(displayIdentifier); final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage, mOverrideSettingsStorage); // Expected settings should be empty because the default is to read from the primary vendor // settings location. SettingsEntry expectedSettings = new SettingsEntry(); assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); // Now switch to secondary vendor settings and assert proper settings. provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage); expectedSettings.mWindowingMode = WINDOWING_MODE_FULLSCREEN; assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); // Switch back to primary and assert settings are empty again. provider.setBaseSettingsStorage(mDefaultVendorSettingsStorage); expectedSettings.mWindowingMode = WINDOWING_MODE_UNDEFINED; assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); } @Test public void testReadingDisplaySettingsFromStorage_overrideSettingsTakePrecedenceOverVendor() { final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId; prepareOverrideDisplaySettings(displayIdentifier); prepareSecondaryDisplaySettings(displayIdentifier); final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage, mOverrideSettingsStorage); provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage); // The windowing mode should be set to WINDOWING_MODE_PINNED because the override settings // take precedence over the vendor provided settings. SettingsEntry expectedSettings = new SettingsEntry(); expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED; assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo())); } @Test public void testWritingDisplaySettingsToStorage() throws Exception { final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo(); // Write some settings to storage. DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider( mBaseSettingsStorage, mOverrideSettingsStorage); mDefaultVendorSettingsStorage, mOverrideSettingsStorage); SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo); overrideSettings.mShouldShowSystemDecors = true; overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL; Loading Loading @@ -195,7 +241,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { // Write some settings to storage. DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider( mBaseSettingsStorage, mOverrideSettingsStorage); mDefaultVendorSettingsStorage, mOverrideSettingsStorage); SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo); overrideSettings.mShouldShowSystemDecors = true; overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL; Loading Loading @@ -236,10 +282,29 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { mOverrideSettingsStorage.setReadStream(is); } /** * Prepares display settings and stores in {@link #mSecondaryVendorSettingsStorage}. Uses * provided display identifier and stores windowingMode=WINDOWING_MODE_FULLSCREEN. */ private void prepareSecondaryDisplaySettings(String displayIdentifier) { String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + "<display-settings>\n"; if (displayIdentifier != null) { contents += " <display\n" + " name=\"" + displayIdentifier + "\"\n" + " windowingMode=\"" + WINDOWING_MODE_FULLSCREEN + "\"/>\n"; } contents += "</display-settings>\n"; final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)); mSecondaryVendorSettingsStorage.setReadStream(is); } private void readAndAssertExpectedSettings(DisplayContent displayContent, SettingsEntry expectedSettings) { final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(mBaseSettingsStorage, mOverrideSettingsStorage); new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage, mOverrideSettingsStorage); assertEquals(expectedSettings, provider.getSettings(displayContent.getDisplayInfo())); } Loading