Merge changes from topic "vendor-display-settings"

* changes:
  Add global development setting to enable/disable vendor display settings. (2/n)
  Seperate out DisplayWindowSettings persistence from retreival/policy logic. (1/n)
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cc3d92d..f31e70a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9773,6 +9773,14 @@
         public static final String DEVELOPMENT_USE_BLAST_ADAPTER_SV =
                 "use_blast_adapter_sv";
 
+        /**
+         * If {@code true}, vendor provided window manager display settings will be ignored.
+         * (0 = false, 1 = true)
+         * @hide
+         */
+        public static final String DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS =
+                "ignore_vendor_display_settings";
+
        /**
         * Whether user has enabled development settings.
         */
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 2412a32..48eb600 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -230,6 +230,7 @@
                     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.DEVICE_DEMO_MODE,
                     Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS,
                     Settings.Global.BATTERY_SAVER_CONSTANTS,
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index f647bea..472678c 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -22,184 +22,41 @@
 
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.WindowConfiguration;
-import android.os.Environment;
-import android.os.FileUtils;
 import android.provider.Settings;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.Xml;
 import android.view.Display;
-import android.view.DisplayAddress;
 import android.view.DisplayInfo;
 import android.view.IWindowManager;
 import android.view.Surface;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.XmlUtils;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.DisplayContent.ForceScalingMode;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
+import java.util.Objects;
 
 /**
- * Current persistent settings about a display
+ * Current persistent settings about a display. Provides policies for display settings and
+ * delegates the persistence and lookup of settings values to the supplied {@link SettingsProvider}.
  */
 class DisplayWindowSettings {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
-
-    private static final String SYSTEM_DIRECTORY = "system";
-    private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml";
-    private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME;
-    private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
-
-    private static final int IDENTIFIER_UNIQUE_ID = 0;
-    private static final int IDENTIFIER_PORT = 1;
-    @IntDef(prefix = { "IDENTIFIER_" }, value = {
-            IDENTIFIER_UNIQUE_ID,
-            IDENTIFIER_PORT,
-    })
-    @interface DisplayIdentifierType {}
-
     private final WindowManagerService mService;
-    private final HashMap<String, Entry> mEntries = new HashMap<>();
-    private final SettingPersister mStorage;
+    private final SettingsProvider mSettingsProvider;
 
-    /**
-     * The preferred type of a display identifier to use when storing and retrieving entries.
-     * {@link #getIdentifier(DisplayInfo)} must be used to get current preferred identifier for each
-     * display. It will fall back to using {@link #IDENTIFIER_UNIQUE_ID} if the currently selected
-     * one is not applicable to a particular display.
-     */
-    @DisplayIdentifierType
-    private int mIdentifier = IDENTIFIER_UNIQUE_ID;
-
-    /** Interface for persisting the display window settings. */
-    interface SettingPersister {
-        InputStream openRead() throws IOException;
-        OutputStream startWrite() throws IOException;
-        void finishWrite(OutputStream os, boolean success);
-    }
-
-    private static class Entry {
-        private final String mName;
-        private int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-        private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
-        private int mUserRotation = Surface.ROTATION_0;
-        private int mForcedWidth;
-        private int mForcedHeight;
-        private int mForcedDensity;
-        private int mForcedScalingMode = FORCE_SCALING_MODE_AUTO;
-        private int mRemoveContentMode = REMOVE_CONTENT_MODE_UNDEFINED;
-        private boolean mShouldShowWithInsecureKeyguard = false;
-        private boolean mShouldShowSystemDecors = false;
-        private boolean mShouldShowIme = false;
-        private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
-        private boolean mIgnoreOrientationRequest = false;
-
-        private Entry(String name) {
-            mName = name;
-        }
-
-        private Entry(String name, Entry copyFrom) {
-            this(name);
-            mWindowingMode = copyFrom.mWindowingMode;
-            mUserRotationMode = copyFrom.mUserRotationMode;
-            mUserRotation = copyFrom.mUserRotation;
-            mForcedWidth = copyFrom.mForcedWidth;
-            mForcedHeight = copyFrom.mForcedHeight;
-            mForcedDensity = copyFrom.mForcedDensity;
-            mForcedScalingMode = copyFrom.mForcedScalingMode;
-            mRemoveContentMode = copyFrom.mRemoveContentMode;
-            mShouldShowWithInsecureKeyguard = copyFrom.mShouldShowWithInsecureKeyguard;
-            mShouldShowSystemDecors = copyFrom.mShouldShowSystemDecors;
-            mShouldShowIme = copyFrom.mShouldShowIme;
-            mFixedToUserRotation = copyFrom.mFixedToUserRotation;
-            mIgnoreOrientationRequest = copyFrom.mIgnoreOrientationRequest;
-        }
-
-        /** @return {@code true} if all values are default. */
-        private boolean isEmpty() {
-            return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
-                    && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
-                    && mUserRotation == Surface.ROTATION_0
-                    && mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
-                    && mForcedScalingMode == FORCE_SCALING_MODE_AUTO
-                    && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
-                    && !mShouldShowWithInsecureKeyguard
-                    && !mShouldShowSystemDecors
-                    && !mShouldShowIme
-                    && mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT
-                    && !mIgnoreOrientationRequest;
-        }
-    }
-
-    DisplayWindowSettings(WindowManagerService service) {
-        this(service, new AtomicFileStorage());
-    }
-
-    @VisibleForTesting
-    DisplayWindowSettings(WindowManagerService service, SettingPersister storageImpl) {
+    DisplayWindowSettings(WindowManagerService service, SettingsProvider settingsProvider) {
         mService = service;
-        mStorage = storageImpl;
-        readSettings();
-    }
-
-    private @Nullable Entry getEntry(DisplayInfo displayInfo) {
-        final String identifier = getIdentifier(displayInfo);
-        Entry entry;
-        // Try to get corresponding entry using preferred identifier for the current config.
-        if ((entry = mEntries.get(identifier)) != null) {
-            return entry;
-        }
-        // Else, fall back to the display name.
-        if ((entry = mEntries.get(displayInfo.name)) != null) {
-            // Found an entry stored with old identifier - upgrade to the new type now.
-            return updateIdentifierForEntry(entry, displayInfo);
-        }
-        return null;
-    }
-
-    private Entry getOrCreateEntry(DisplayInfo displayInfo) {
-        final Entry entry = getEntry(displayInfo);
-        return entry != null ? entry : new Entry(getIdentifier(displayInfo));
-    }
-
-    /**
-     * Upgrades the identifier of a legacy entry. Does it by copying the data from the old record
-     * and clearing the old key in memory. The entry will be written to storage next time when a
-     * setting changes.
-     */
-    private Entry updateIdentifierForEntry(Entry entry, DisplayInfo displayInfo) {
-        final Entry newEntry = new Entry(getIdentifier(displayInfo), entry);
-        removeEntry(displayInfo);
-        mEntries.put(newEntry.mName, newEntry);
-        return newEntry;
+        mSettingsProvider = settingsProvider;
     }
 
     void setUserRotation(DisplayContent displayContent, int rotationMode, int rotation) {
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mUserRotationMode = rotationMode;
-        entry.mUserRotation = rotation;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mUserRotationMode = rotationMode;
+        overrideSettings.mUserRotation = rotation;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     void setForcedSize(DisplayContent displayContent, int width, int height) {
@@ -207,14 +64,14 @@
             final String sizeString = (width == 0 || height == 0) ? "" : (width + "," + height);
             Settings.Global.putString(mService.mContext.getContentResolver(),
                     Settings.Global.DISPLAY_SIZE_FORCED, sizeString);
-            return;
         }
 
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mForcedWidth = width;
-        entry.mForcedHeight = height;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mForcedWidth = width;
+        overrideSettings.mForcedHeight = height;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     void setForcedDensity(DisplayContent displayContent, int density, int userId) {
@@ -222,47 +79,47 @@
             final String densityString = density == 0 ? "" : Integer.toString(density);
             Settings.Secure.putStringForUser(mService.mContext.getContentResolver(),
                     Settings.Secure.DISPLAY_DENSITY_FORCED, densityString, userId);
-            return;
         }
 
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mForcedDensity = density;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mForcedDensity = density;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     void setForcedScalingMode(DisplayContent displayContent, @ForceScalingMode int mode) {
         if (displayContent.isDefaultDisplay) {
             Settings.Global.putInt(mService.mContext.getContentResolver(),
                     Settings.Global.DISPLAY_SCALING_FORCE, mode);
-            return;
         }
 
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mForcedScalingMode = mode;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mForcedScalingMode = mode;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     void setFixedToUserRotation(DisplayContent displayContent, int fixedToUserRotation) {
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mFixedToUserRotation = fixedToUserRotation;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mFixedToUserRotation = fixedToUserRotation;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     void setIgnoreOrientationRequest(
             DisplayContent displayContent, boolean ignoreOrientationRequest) {
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        if (entry.mIgnoreOrientationRequest == ignoreOrientationRequest) return;
-        entry.mIgnoreOrientationRequest = ignoreOrientationRequest;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mIgnoreOrientationRequest = ignoreOrientationRequest;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
-    private int getWindowingModeLocked(Entry entry, DisplayContent dc) {
-        int windowingMode = entry != null ? entry.mWindowingMode
-                : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+    private int getWindowingModeLocked(SettingsProvider.SettingsEntry settings, DisplayContent dc) {
+        int windowingMode = settings.mWindowingMode;
         // This display used to be in freeform, but we don't support freeform anymore, so fall
         // back to fullscreen.
         if (windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -281,22 +138,23 @@
 
     int getWindowingModeLocked(DisplayContent dc) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getEntry(displayInfo);
-        return getWindowingModeLocked(entry, dc);
+        final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+        return getWindowingModeLocked(settings, dc);
     }
 
     void setWindowingModeLocked(DisplayContent dc, int mode) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mWindowingMode = mode;
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mWindowingMode = mode;
         dc.setWindowingMode(mode);
-        writeSettingsIfNeeded(entry, displayInfo);
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     int getRemoveContentModeLocked(DisplayContent dc) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getEntry(displayInfo);
-        if (entry == null || entry.mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED) {
+        final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+        if (settings.mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED) {
             if (dc.isPrivate()) {
                 // For private displays by default content is destroyed on removal.
                 return REMOVE_CONTENT_MODE_DESTROY;
@@ -304,111 +162,110 @@
             // For other displays by default content is moved to primary on removal.
             return REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
         }
-        return entry.mRemoveContentMode;
+        return settings.mRemoveContentMode;
     }
 
     void setRemoveContentModeLocked(DisplayContent dc, int mode) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mRemoveContentMode = mode;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mRemoveContentMode = mode;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     boolean shouldShowWithInsecureKeyguardLocked(DisplayContent dc) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getEntry(displayInfo);
-        if (entry == null) {
-            return false;
-        }
-        return entry.mShouldShowWithInsecureKeyguard;
+        final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+        return settings.mShouldShowWithInsecureKeyguard != null
+                ? settings.mShouldShowWithInsecureKeyguard : false;
     }
 
     void setShouldShowWithInsecureKeyguardLocked(DisplayContent dc, boolean shouldShow) {
         if (!dc.isPrivate() && shouldShow) {
-            Slog.e(TAG, "Public display can't be allowed to show content when locked");
-            return;
+            throw new IllegalArgumentException("Public display can't be allowed to show content"
+                    + " when locked");
         }
 
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mShouldShowWithInsecureKeyguard = shouldShow;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mShouldShowWithInsecureKeyguard = shouldShow;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     boolean shouldShowSystemDecorsLocked(DisplayContent dc) {
         if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
-            // For default display should show system decors.
+            // Default display should show system decors.
             return true;
         }
 
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getEntry(displayInfo);
-        if (entry == null) {
-            return false;
-        }
-        return entry.mShouldShowSystemDecors;
+        final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+        return settings.mShouldShowSystemDecors != null ? settings.mShouldShowSystemDecors : false;
     }
 
     void setShouldShowSystemDecorsLocked(DisplayContent dc, boolean shouldShow) {
-        if (dc.getDisplayId() == Display.DEFAULT_DISPLAY && !shouldShow) {
-            Slog.e(TAG, "Default display should show system decors");
-            return;
-        }
-
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mShouldShowSystemDecors = shouldShow;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mShouldShowSystemDecors = shouldShow;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     boolean shouldShowImeLocked(DisplayContent dc) {
         if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
-            // For default display should shows IME.
+            // Default display should show IME.
             return true;
         }
 
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getEntry(displayInfo);
-        if (entry == null) {
-            return false;
-        }
-        return entry.mShouldShowIme;
+        final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+        return settings.mShouldShowIme != null ? settings.mShouldShowIme : false;
     }
 
     void setShouldShowImeLocked(DisplayContent dc, boolean shouldShow) {
-        if (dc.getDisplayId() == Display.DEFAULT_DISPLAY && !shouldShow) {
-            Slog.e(TAG, "Default display should show IME");
-            return;
-        }
-
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mShouldShowIme = shouldShow;
-        writeSettingsIfNeeded(entry, displayInfo);
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mShouldShowIme = shouldShow;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
     void applySettingsToDisplayLocked(DisplayContent dc) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getOrCreateEntry(displayInfo);
+        final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
 
         // Setting windowing mode first, because it may override overscan values later.
-        dc.setWindowingMode(getWindowingModeLocked(entry, dc));
+        final int windowingMode = getWindowingModeLocked(settings, dc);
+        dc.setWindowingMode(windowingMode);
 
-        dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode,
-                entry.mUserRotation, entry.mFixedToUserRotation);
+        final int userRotationMode = settings.mUserRotationMode != null
+                ? settings.mUserRotationMode : WindowManagerPolicy.USER_ROTATION_FREE;
+        final int userRotation = settings.mUserRotation != null
+                ? settings.mUserRotation : Surface.ROTATION_0;
+        final int mFixedToUserRotation = settings.mFixedToUserRotation != null
+                ? settings.mFixedToUserRotation : IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
+        dc.getDisplayRotation().restoreSettings(userRotationMode, userRotation,
+                mFixedToUserRotation);
 
-        final boolean hasDensityOverride = entry.mForcedDensity != 0;
-        final boolean hasSizeOverride = entry.mForcedWidth != 0 && entry.mForcedHeight != 0;
+        final boolean hasDensityOverride = settings.mForcedDensity != 0;
+        final boolean hasSizeOverride = settings.mForcedWidth != 0 && settings.mForcedHeight != 0;
         dc.mIsDensityForced = hasDensityOverride;
         dc.mIsSizeForced = hasSizeOverride;
-        dc.setIgnoreOrientationRequest(entry.mIgnoreOrientationRequest);
 
-        final int width = hasSizeOverride ? entry.mForcedWidth : dc.mBaseDisplayWidth;
-        final int height = hasSizeOverride ? entry.mForcedHeight : dc.mBaseDisplayHeight;
-        final int density = hasDensityOverride ? entry.mForcedDensity : dc.mBaseDisplayDensity;
+        final boolean ignoreOrientationRequest = settings.mIgnoreOrientationRequest != null
+                ? settings.mIgnoreOrientationRequest : false;
+        dc.setIgnoreOrientationRequest(ignoreOrientationRequest);
+
+        final int width = hasSizeOverride ? settings.mForcedWidth : dc.mInitialDisplayWidth;
+        final int height = hasSizeOverride ? settings.mForcedHeight : dc.mInitialDisplayHeight;
+        final int density = hasDensityOverride ? settings.mForcedDensity
+                : dc.mInitialDisplayDensity;
         dc.updateBaseDisplayMetrics(width, height, density);
 
-        dc.mDisplayScalingDisabled = entry.mForcedScalingMode == FORCE_SCALING_MODE_DISABLED;
+        final int forcedScalingMode = settings.mForcedScalingMode != null
+                ? settings.mForcedScalingMode : FORCE_SCALING_MODE_AUTO;
+        dc.mDisplayScalingDisabled = forcedScalingMode == FORCE_SCALING_MODE_DISABLED;
     }
 
     /**
@@ -429,291 +286,281 @@
         return false;
     }
 
-    private void readSettings() {
-        InputStream stream;
-        try {
-            stream = mStorage.openRead();
-        } catch (IOException e) {
-            Slog.i(TAG, "No existing display settings, starting empty");
-            return;
-        }
-        boolean success = false;
-        try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(stream, StandardCharsets.UTF_8.name());
-            int type;
-            while ((type = parser.next()) != XmlPullParser.START_TAG
-                    && type != XmlPullParser.END_DOCUMENT) {
-                // Do nothing.
-            }
-
-            if (type != XmlPullParser.START_TAG) {
-                throw new IllegalStateException("no start tag found");
-            }
-
-            int outerDepth = parser.getDepth();
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-
-                String tagName = parser.getName();
-                if (tagName.equals("display")) {
-                    readDisplay(parser);
-                } else if (tagName.equals("config")) {
-                    readConfig(parser);
-                } else {
-                    Slog.w(TAG, "Unknown element under <display-settings>: "
-                            + parser.getName());
-                    XmlUtils.skipCurrentTag(parser);
-                }
-            }
-            success = true;
-        } catch (IllegalStateException e) {
-            Slog.w(TAG, "Failed parsing " + e);
-        } catch (NullPointerException e) {
-            Slog.w(TAG, "Failed parsing " + e);
-        } catch (NumberFormatException e) {
-            Slog.w(TAG, "Failed parsing " + e);
-        } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Failed parsing " + e);
-        } catch (IOException e) {
-            Slog.w(TAG, "Failed parsing " + e);
-        } catch (IndexOutOfBoundsException e) {
-            Slog.w(TAG, "Failed parsing " + e);
-        } finally {
-            if (!success) {
-                mEntries.clear();
-            }
-            try {
-                stream.close();
-            } catch (IOException e) {
-            }
-        }
-    }
-
-    private int getIntAttribute(XmlPullParser parser, String name) {
-        return getIntAttribute(parser, name, 0 /* defaultValue */);
-    }
-
-    private int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
-        try {
-            final String str = parser.getAttributeValue(null, name);
-            return str != null ? Integer.parseInt(str) : defaultValue;
-        } catch (NumberFormatException e) {
-            return defaultValue;
-        }
-    }
-
-    private boolean getBooleanAttribute(XmlPullParser parser, String name) {
-        return getBooleanAttribute(parser, name, false /* defaultValue */);
-    }
-
-    private boolean getBooleanAttribute(XmlPullParser parser, String name, boolean defaultValue) {
-        try {
-            final String str = parser.getAttributeValue(null, name);
-            return str != null ? Boolean.parseBoolean(str) : defaultValue;
-        } catch (NumberFormatException e) {
-            return defaultValue;
-        }
-    }
-
-    private void readDisplay(XmlPullParser parser) throws NumberFormatException,
-            XmlPullParserException, IOException {
-        String name = parser.getAttributeValue(null, "name");
-        if (name != null) {
-            Entry entry = new Entry(name);
-            entry.mWindowingMode = getIntAttribute(parser, "windowingMode",
-                    WindowConfiguration.WINDOWING_MODE_UNDEFINED);
-            entry.mUserRotationMode = getIntAttribute(parser, "userRotationMode",
-                    WindowManagerPolicy.USER_ROTATION_FREE);
-            entry.mUserRotation = getIntAttribute(parser, "userRotation",
-                    Surface.ROTATION_0);
-            entry.mForcedWidth = getIntAttribute(parser, "forcedWidth");
-            entry.mForcedHeight = getIntAttribute(parser, "forcedHeight");
-            entry.mForcedDensity = getIntAttribute(parser, "forcedDensity");
-            entry.mForcedScalingMode = getIntAttribute(parser, "forcedScalingMode",
-                    FORCE_SCALING_MODE_AUTO);
-            entry.mRemoveContentMode = getIntAttribute(parser, "removeContentMode",
-                    REMOVE_CONTENT_MODE_UNDEFINED);
-            entry.mShouldShowWithInsecureKeyguard = getBooleanAttribute(parser,
-                    "shouldShowWithInsecureKeyguard");
-            entry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors");
-            entry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme");
-            entry.mFixedToUserRotation = getIntAttribute(parser, "fixedToUserRotation");
-            entry.mIgnoreOrientationRequest
-                    = getBooleanAttribute(parser, "ignoreOrientationRequest");
-            mEntries.put(name, entry);
-        }
-        XmlUtils.skipCurrentTag(parser);
-    }
-
-    private void readConfig(XmlPullParser parser) throws NumberFormatException,
-            XmlPullParserException, IOException {
-        mIdentifier = getIntAttribute(parser, "identifier");
-        XmlUtils.skipCurrentTag(parser);
-    }
-
-    private void writeSettingsIfNeeded(Entry changedEntry, DisplayInfo displayInfo) {
-        if (changedEntry.isEmpty() && !removeEntry(displayInfo)) {
-            // The entry didn't exist so nothing is changed and no need to update the file.
-            return;
-        }
-
-        mEntries.put(getIdentifier(displayInfo), changedEntry);
-        writeSettings();
-    }
-
-    private void writeSettings() {
-        OutputStream stream;
-        try {
-            stream = mStorage.startWrite();
-        } catch (IOException e) {
-            Slog.w(TAG, "Failed to write display settings: " + e);
-            return;
-        }
-
-        try {
-            XmlSerializer out = new FastXmlSerializer();
-            out.setOutput(stream, StandardCharsets.UTF_8.name());
-            out.startDocument(null, true);
-
-            out.startTag(null, "display-settings");
-
-            out.startTag(null, "config");
-            out.attribute(null, "identifier", Integer.toString(mIdentifier));
-            out.endTag(null, "config");
-
-            for (Entry entry : mEntries.values()) {
-                out.startTag(null, "display");
-                out.attribute(null, "name", entry.mName);
-                if (entry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
-                    out.attribute(null, "windowingMode", Integer.toString(entry.mWindowingMode));
-                }
-                if (entry.mUserRotationMode != WindowManagerPolicy.USER_ROTATION_FREE) {
-                    out.attribute(null, "userRotationMode",
-                            Integer.toString(entry.mUserRotationMode));
-                }
-                if (entry.mUserRotation != Surface.ROTATION_0) {
-                    out.attribute(null, "userRotation", Integer.toString(entry.mUserRotation));
-                }
-                if (entry.mForcedWidth != 0 && entry.mForcedHeight != 0) {
-                    out.attribute(null, "forcedWidth", Integer.toString(entry.mForcedWidth));
-                    out.attribute(null, "forcedHeight", Integer.toString(entry.mForcedHeight));
-                }
-                if (entry.mForcedDensity != 0) {
-                    out.attribute(null, "forcedDensity", Integer.toString(entry.mForcedDensity));
-                }
-                if (entry.mForcedScalingMode != FORCE_SCALING_MODE_AUTO) {
-                    out.attribute(null, "forcedScalingMode",
-                            Integer.toString(entry.mForcedScalingMode));
-                }
-                if (entry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
-                    out.attribute(null, "removeContentMode",
-                            Integer.toString(entry.mRemoveContentMode));
-                }
-                if (entry.mShouldShowWithInsecureKeyguard) {
-                    out.attribute(null, "shouldShowWithInsecureKeyguard",
-                            Boolean.toString(entry.mShouldShowWithInsecureKeyguard));
-                }
-                if (entry.mShouldShowSystemDecors) {
-                    out.attribute(null, "shouldShowSystemDecors",
-                            Boolean.toString(entry.mShouldShowSystemDecors));
-                }
-                if (entry.mShouldShowIme) {
-                    out.attribute(null, "shouldShowIme", Boolean.toString(entry.mShouldShowIme));
-                }
-                if (entry.mFixedToUserRotation != IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT) {
-                    out.attribute(null, "fixedToUserRotation",
-                            Integer.toString(entry.mFixedToUserRotation));
-                }
-                if (entry.mIgnoreOrientationRequest) {
-                    out.attribute(null, "ignoreOrientationRequest",
-                            Boolean.toString(entry.mIgnoreOrientationRequest));
-                }
-                out.endTag(null, "display");
-            }
-
-            out.endTag(null, "display-settings");
-            out.endDocument();
-            mStorage.finishWrite(stream, true /* success */);
-        } catch (IOException e) {
-            Slog.w(TAG, "Failed to write display window settings.", e);
-            mStorage.finishWrite(stream, false /* success */);
-        }
-    }
-
     /**
-     * Removes an entry from {@link #mEntries} cache. Looks up by new and previously used
-     * identifiers.
+     * Provides the functionality to lookup the {@link SettingsEntry settings} for a given
+     * {@link DisplayInfo}.
+     * <p>
+     * NOTE: All interactions with implementations of this provider <b>must</b> be thread-safe
+     * externally.
      */
-    private boolean removeEntry(DisplayInfo displayInfo) {
-        // Remove entry based on primary identifier.
-        boolean removed = mEntries.remove(getIdentifier(displayInfo)) != null;
-        // Ensure that legacy entries are cleared as well.
-        removed |= mEntries.remove(displayInfo.uniqueId) != null;
-        removed |= mEntries.remove(displayInfo.name) != null;
-        return removed;
-    }
+    interface SettingsProvider {
+        /**
+         * Returns the {@link SettingsEntry} for a given {@link DisplayInfo}. The values for the
+         * returned settings are guaranteed to match those previously set with
+         * {@link #updateOverrideSettings(DisplayInfo, SettingsEntry)} with all other values left
+         * to the implementation to determine.
+         */
+        @NonNull
+        SettingsEntry getSettings(@NonNull DisplayInfo info);
 
-    /** Gets the identifier of choice for the current config. */
-    private String getIdentifier(DisplayInfo displayInfo) {
-        if (mIdentifier == 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();
+        /**
+         * Returns the existing override settings for the given {@link DisplayInfo}. All calls to
+         * {@link #getSettings(DisplayInfo)} for the provided {@code info} are required to have
+         * their values overridden with all set values from the returned {@link SettingsEntry}.
+         *
+         * @see #getSettings(DisplayInfo)
+         * @see #updateOverrideSettings(DisplayInfo, SettingsEntry)
+         */
+        @NonNull
+        SettingsEntry getOverrideSettings(@NonNull DisplayInfo info);
+
+        /**
+         * Updates the override settings for a given {@link DisplayInfo}. All subsequent calls to
+         * {@link #getSettings(DisplayInfo)} for the provided {@link DisplayInfo} are required to
+         * have their values match all set values in {@code overrides}.
+         *
+         * @see #getSettings(DisplayInfo)
+         */
+        void updateOverrideSettings(@NonNull DisplayInfo info, @NonNull SettingsEntry overrides);
+
+        /**
+         * Settings for a display.
+         */
+        class SettingsEntry {
+            int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+            @Nullable
+            Integer mUserRotationMode;
+            @Nullable
+            Integer mUserRotation;
+            int mForcedWidth;
+            int mForcedHeight;
+            int mForcedDensity;
+            @Nullable
+            Integer mForcedScalingMode;
+            int mRemoveContentMode = REMOVE_CONTENT_MODE_UNDEFINED;
+            @Nullable
+            Boolean mShouldShowWithInsecureKeyguard;
+            @Nullable
+            Boolean mShouldShowSystemDecors;
+            @Nullable
+            Boolean mShouldShowIme;
+            @Nullable
+            Integer mFixedToUserRotation;
+            @Nullable
+            Boolean mIgnoreOrientationRequest;
+
+            SettingsEntry() {}
+
+            SettingsEntry(SettingsEntry copyFrom) {
+                setTo(copyFrom);
             }
-        }
-        return displayInfo.uniqueId;
-    }
 
-    private static class AtomicFileStorage implements SettingPersister {
-        private final AtomicFile mAtomicFile;
-
-        AtomicFileStorage() {
-            final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY);
-            final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME);
-            // If display_settings.xml doesn't exist, try to copy the vendor's one instead
-            // in order to provide the vendor specific initialization.
-            if (!settingsFile.exists()) {
-                copyVendorSettings(settingsFile);
-            }
-            mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG);
-        }
-
-        private static void copyVendorSettings(File target) {
-            final File vendorFile = new File(Environment.getVendorDirectory(),
-                    VENDOR_DISPLAY_SETTINGS_PATH);
-            if (vendorFile.canRead()) {
-                try {
-                    FileUtils.copy(vendorFile, target);
-                } catch (IOException e) {
-                    Slog.e(TAG, "Failed to copy vendor display_settings.xml");
+            /**
+             * Copies all fields from {@code delta} into this {@link SettingsEntry} object, keeping
+             * track of whether a change has occurred.
+             *
+             * @return {@code true} if this settings have changed as a result of the copy,
+             *         {@code false} otherwise.
+             *
+             * @see #updateFrom(SettingsEntry)
+             */
+            boolean setTo(@NonNull SettingsEntry other) {
+                boolean changed = false;
+                if (other.mWindowingMode != mWindowingMode) {
+                    mWindowingMode = other.mWindowingMode;
+                    changed = true;
                 }
+                if (!Objects.equals(other.mUserRotationMode, mUserRotationMode)) {
+                    mUserRotationMode = other.mUserRotationMode;
+                    changed = true;
+                }
+                if (!Objects.equals(other.mUserRotation, mUserRotation)) {
+                    mUserRotation = other.mUserRotation;
+                    changed = true;
+                }
+                if (other.mForcedWidth != mForcedWidth) {
+                    mForcedWidth = other.mForcedWidth;
+                    changed = true;
+                }
+                if (other.mForcedHeight != mForcedHeight) {
+                    mForcedHeight = other.mForcedHeight;
+                    changed = true;
+                }
+                if (other.mForcedDensity != mForcedDensity) {
+                    mForcedDensity = other.mForcedDensity;
+                    changed = true;
+                }
+                if (!Objects.equals(other.mForcedScalingMode, mForcedScalingMode)) {
+                    mForcedScalingMode = other.mForcedScalingMode;
+                    changed = true;
+                }
+                if (other.mRemoveContentMode != mRemoveContentMode) {
+                    mRemoveContentMode = other.mRemoveContentMode;
+                    changed = true;
+                }
+                if (other.mShouldShowWithInsecureKeyguard != mShouldShowWithInsecureKeyguard) {
+                    mShouldShowWithInsecureKeyguard = other.mShouldShowWithInsecureKeyguard;
+                    changed = true;
+                }
+                if (other.mShouldShowSystemDecors != mShouldShowSystemDecors) {
+                    mShouldShowSystemDecors = other.mShouldShowSystemDecors;
+                    changed = true;
+                }
+                if (other.mShouldShowIme != mShouldShowIme) {
+                    mShouldShowIme = other.mShouldShowIme;
+                    changed = true;
+                }
+                if (!Objects.equals(other.mFixedToUserRotation, mFixedToUserRotation)) {
+                    mFixedToUserRotation = other.mFixedToUserRotation;
+                    changed = true;
+                }
+                if (other.mIgnoreOrientationRequest != mIgnoreOrientationRequest) {
+                    mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
+                    changed = true;
+                }
+                return changed;
             }
-        }
 
-        @Override
-        public InputStream openRead() throws FileNotFoundException {
-            return mAtomicFile.openRead();
-        }
-
-        @Override
-        public OutputStream startWrite() throws IOException {
-            return mAtomicFile.startWrite();
-        }
-
-        @Override
-        public void finishWrite(OutputStream os, boolean success) {
-            if (!(os instanceof FileOutputStream)) {
-                throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
+            /**
+             * Copies the fields from {@code delta} into this {@link SettingsEntry} object, keeping
+             * track of whether a change has occurred. Any undefined fields in {@code delta} are
+             * ignored and not copied into the current {@link SettingsEntry}.
+             *
+             * @return {@code true} if this settings have changed as a result of the copy,
+             *         {@code false} otherwise.
+             *
+             * @see #setTo(SettingsEntry)
+             */
+            boolean updateFrom(@NonNull SettingsEntry delta) {
+                boolean changed = false;
+                if (delta.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED
+                        && delta.mWindowingMode != mWindowingMode) {
+                    mWindowingMode = delta.mWindowingMode;
+                    changed = true;
+                }
+                if (delta.mUserRotationMode != null
+                        && !Objects.equals(delta.mUserRotationMode, mUserRotationMode)) {
+                    mUserRotationMode = delta.mUserRotationMode;
+                    changed = true;
+                }
+                if (delta.mUserRotation != null
+                        && !Objects.equals(delta.mUserRotation, mUserRotation)) {
+                    mUserRotation = delta.mUserRotation;
+                    changed = true;
+                }
+                if (delta.mForcedWidth != 0 && delta.mForcedWidth != mForcedWidth) {
+                    mForcedWidth = delta.mForcedWidth;
+                    changed = true;
+                }
+                if (delta.mForcedHeight != 0 && delta.mForcedHeight != mForcedHeight) {
+                    mForcedHeight = delta.mForcedHeight;
+                    changed = true;
+                }
+                if (delta.mForcedDensity != 0 && delta.mForcedDensity != mForcedDensity) {
+                    mForcedDensity = delta.mForcedDensity;
+                    changed = true;
+                }
+                if (delta.mForcedScalingMode != null
+                        && !Objects.equals(delta.mForcedScalingMode, mForcedScalingMode)) {
+                    mForcedScalingMode = delta.mForcedScalingMode;
+                    changed = true;
+                }
+                if (delta.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED
+                        && delta.mRemoveContentMode != mRemoveContentMode) {
+                    mRemoveContentMode = delta.mRemoveContentMode;
+                    changed = true;
+                }
+                if (delta.mShouldShowWithInsecureKeyguard != null
+                        && delta.mShouldShowWithInsecureKeyguard
+                        != mShouldShowWithInsecureKeyguard) {
+                    mShouldShowWithInsecureKeyguard = delta.mShouldShowWithInsecureKeyguard;
+                    changed = true;
+                }
+                if (delta.mShouldShowSystemDecors != null
+                        && delta.mShouldShowSystemDecors != mShouldShowSystemDecors) {
+                    mShouldShowSystemDecors = delta.mShouldShowSystemDecors;
+                    changed = true;
+                }
+                if (delta.mShouldShowIme != null
+                        && delta.mShouldShowIme != mShouldShowIme) {
+                    mShouldShowIme = delta.mShouldShowIme;
+                    changed = true;
+                }
+                if (delta.mFixedToUserRotation != null
+                        && !Objects.equals(delta.mFixedToUserRotation, mFixedToUserRotation)) {
+                    mFixedToUserRotation = delta.mFixedToUserRotation;
+                    changed = true;
+                }
+                if (delta.mIgnoreOrientationRequest != null
+                        && delta.mIgnoreOrientationRequest != mIgnoreOrientationRequest) {
+                    mIgnoreOrientationRequest = delta.mIgnoreOrientationRequest;
+                    changed = true;
+                }
+                return changed;
             }
-            FileOutputStream fos = (FileOutputStream) os;
-            if (success) {
-                mAtomicFile.finishWrite(fos);
-            } else {
-                mAtomicFile.failWrite(fos);
+
+            /** @return {@code true} if all values are unset. */
+            boolean isEmpty() {
+                return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+                        && mUserRotationMode == null
+                        && mUserRotation == null
+                        && mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
+                        && mForcedScalingMode == null
+                        && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
+                        && mShouldShowWithInsecureKeyguard == null
+                        && mShouldShowSystemDecors == null
+                        && mShouldShowIme == null
+                        && mFixedToUserRotation == null
+                        && mIgnoreOrientationRequest == null;
+            }
+
+            @Override
+            public boolean equals(@Nullable Object o) {
+                if (this == o) return true;
+                if (o == null || getClass() != o.getClass()) return false;
+                SettingsEntry that = (SettingsEntry) o;
+                return mWindowingMode == that.mWindowingMode
+                        && mForcedWidth == that.mForcedWidth
+                        && mForcedHeight == that.mForcedHeight
+                        && mForcedDensity == that.mForcedDensity
+                        && mRemoveContentMode == that.mRemoveContentMode
+                        && Objects.equals(mUserRotationMode, that.mUserRotationMode)
+                        && Objects.equals(mUserRotation, that.mUserRotation)
+                        && Objects.equals(mForcedScalingMode, that.mForcedScalingMode)
+                        && Objects.equals(mShouldShowWithInsecureKeyguard,
+                                that.mShouldShowWithInsecureKeyguard)
+                        && Objects.equals(mShouldShowSystemDecors, that.mShouldShowSystemDecors)
+                        && Objects.equals(mShouldShowIme, that.mShouldShowIme)
+                        && Objects.equals(mFixedToUserRotation, that.mFixedToUserRotation)
+                        && Objects.equals(mIgnoreOrientationRequest,
+                                that.mIgnoreOrientationRequest);
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(mWindowingMode, mUserRotationMode, mUserRotation, mForcedWidth,
+                        mForcedHeight, mForcedDensity, mForcedScalingMode, mRemoveContentMode,
+                        mShouldShowWithInsecureKeyguard, mShouldShowSystemDecors, mShouldShowIme,
+                        mFixedToUserRotation, mIgnoreOrientationRequest);
+            }
+
+            @Override
+            public String toString() {
+                return "SettingsEntry{"
+                        + "mWindowingMode=" + mWindowingMode
+                        + ", mUserRotationMode=" + mUserRotationMode
+                        + ", mUserRotation=" + mUserRotation
+                        + ", mForcedWidth=" + mForcedWidth
+                        + ", mForcedHeight=" + mForcedHeight
+                        + ", mForcedDensity=" + mForcedDensity
+                        + ", mForcedScalingMode=" + mForcedScalingMode
+                        + ", mRemoveContentMode=" + mRemoveContentMode
+                        + ", mShouldShowWithInsecureKeyguard=" + mShouldShowWithInsecureKeyguard
+                        + ", mShouldShowSystemDecors=" + mShouldShowSystemDecors
+                        + ", mShouldShowIme=" + mShouldShowIme
+                        + ", mFixedToUserRotation=" + mFixedToUserRotation
+                        + ", mIgnoreOrientationRequest=" + mIgnoreOrientationRequest
+                        + '}';
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
new file mode 100644
index 0000000..a7f7c48
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of {@link SettingsProvider} that reads the base settings provided in a display
+ * settings file stored in /vendor/etc and then overlays those values with the settings provided in
+ * /data/system.
+ *
+ * @see DisplayWindowSettings
+ */
+class DisplayWindowSettingsProvider implements SettingsProvider {
+    private static final String TAG = TAG_WITH_CLASS_NAME
+            ? "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 WM_DISPLAY_COMMIT_TAG = "wm-displays";
+
+    private static final int IDENTIFIER_UNIQUE_ID = 0;
+    private static final int IDENTIFIER_PORT = 1;
+    @IntDef(prefix = { "IDENTIFIER_" }, value = {
+            IDENTIFIER_UNIQUE_ID,
+            IDENTIFIER_PORT,
+    })
+    @interface DisplayIdentifierType {}
+
+    /** Interface that allows reading the display window settings. */
+    interface ReadableSettingsStorage {
+        InputStream openRead() throws IOException;
+    }
+
+    /** Interface that allows reading and writing the display window settings. */
+    interface WritableSettingsStorage extends ReadableSettingsStorage {
+        OutputStream startWrite() throws IOException;
+        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;
+
+    DisplayWindowSettingsProvider() {
+        this(new AtomicFileStorage(getVendorSettingsFile()),
+                new AtomicFileStorage(getOverrideSettingsFile()));
+    }
+
+    @VisibleForTesting
+    DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage vendorSettingsStorage,
+            @NonNull WritableSettingsStorage overrideSettingsStorage) {
+        mVendorSettingsStorage = vendorSettingsStorage;
+        mOverrideSettingsStorage = overrideSettingsStorage;
+        readSettings();
+    }
+
+    /**
+     * 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.
+     */
+    void setVendorSettingsIgnored(boolean ignored) {
+        mIgnoreVendorSettings = ignored;
+    }
+
+    /**
+     * Returns whether or not the vendor settings are being ignored.
+     *
+     * @see #setVendorSettingsIgnored(boolean)
+     */
+    @VisibleForTesting
+    boolean getVendorSettingsIgnored() {
+        return mIgnoreVendorSettings;
+    }
+
+    @Override
+    @NonNull
+    public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+        SettingsEntry vendorSettings = getVendorSettingsEntry(info);
+        SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+        if (vendorSettings == null) {
+            return new SettingsEntry(overrideSettings);
+        } else {
+            SettingsEntry mergedSettings = new SettingsEntry(vendorSettings);
+            mergedSettings.updateFrom(overrideSettings);
+            return mergedSettings;
+        }
+    }
+
+    @Override
+    @NonNull
+    public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+        return new SettingsEntry(getOrCreateOverrideSettingsEntry(info));
+    }
+
+    @Override
+    public void updateOverrideSettings(@NonNull DisplayInfo info,
+            @NonNull SettingsEntry overrides) {
+        final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+        boolean changed = overrideSettings.setTo(overrides);
+        if (changed) {
+            writeOverrideSettings();
+        }
+    }
+
+    @Nullable
+    private SettingsEntry getVendorSettingsEntry(DisplayInfo info) {
+        if (mIgnoreVendorSettings) {
+            return null;
+        }
+
+        final String identifier = getIdentifier(info, mVendorIdentifierType);
+        SettingsEntry settings;
+        // Try to get corresponding settings using preferred identifier for the current config.
+        if ((settings = mVendorSettings.get(identifier)) != null) {
+            return settings;
+        }
+        // Else, fall back to the display name.
+        if ((settings = mVendorSettings.get(info.name)) != null) {
+            // Found an entry stored with old identifier.
+            mVendorSettings.remove(info.name);
+            mVendorSettings.put(identifier, settings);
+            return settings;
+        }
+        return null;
+    }
+
+    @NonNull
+    private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) {
+        final String identifier = getIdentifier(info, mOverrideIdentifierType);
+        SettingsEntry settings;
+        // Try to get corresponding settings using preferred identifier for the current config.
+        if ((settings = mOverrideSettings.get(identifier)) != null) {
+            return settings;
+        }
+        // Else, fall back to the display name.
+        if ((settings = mOverrideSettings.get(info.name)) != null) {
+            // Found an entry stored with old identifier.
+            mOverrideSettings.remove(info.name);
+            mOverrideSettings.put(identifier, settings);
+            writeOverrideSettings();
+            return settings;
+        }
+
+        settings = new SettingsEntry();
+        mOverrideSettings.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);
+        }
+    }
+
+    private void writeOverrideSettings() {
+        FileData fileData = new FileData();
+        fileData.mIdentifierType = mOverrideIdentifierType;
+        fileData.mSettings.putAll(mOverrideSettings);
+        writeSettings(mOverrideSettingsStorage, 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);
+        return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG);
+    }
+
+    @NonNull
+    private static AtomicFile getOverrideSettingsFile() {
+        final File overrideSettingsFile = new File(Environment.getDataDirectory(),
+                DATA_DISPLAY_SETTINGS_FILE_PATH);
+        return new AtomicFile(overrideSettingsFile, WM_DISPLAY_COMMIT_TAG);
+    }
+
+    @Nullable
+    private static FileData readSettings(ReadableSettingsStorage storage) {
+        InputStream stream;
+        try {
+            stream = storage.openRead();
+        } catch (IOException e) {
+            Slog.i(TAG, "No existing display settings, starting empty");
+            return null;
+        }
+        FileData fileData = new FileData();
+        boolean success = false;
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                // Do nothing.
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new IllegalStateException("no start tag found");
+            }
+
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals("display")) {
+                    readDisplay(parser, fileData);
+                } else if (tagName.equals("config")) {
+                    readConfig(parser, fileData);
+                } else {
+                    Slog.w(TAG, "Unknown element under <display-settings>: "
+                            + parser.getName());
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+            success = true;
+        } catch (IllegalStateException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (IndexOutOfBoundsException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } finally {
+            try {
+                stream.close();
+            } catch (IOException ignored) {
+            }
+        }
+        if (!success) {
+            fileData.mSettings.clear();
+        }
+        return fileData;
+    }
+
+    private static int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
+        try {
+            final String str = parser.getAttributeValue(null, name);
+            return str != null ? Integer.parseInt(str) : defaultValue;
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+            return defaultValue;
+        }
+    }
+
+    @Nullable
+    private static Integer getIntegerAttribute(XmlPullParser parser, String name,
+            @Nullable Integer defaultValue) {
+        try {
+            final String str = parser.getAttributeValue(null, name);
+            return str != null ? Integer.valueOf(str) : defaultValue;
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+            return defaultValue;
+        }
+    }
+
+    @Nullable
+    private static Boolean getBooleanAttribute(XmlPullParser parser, String name,
+            @Nullable Boolean defaultValue) {
+        final String str = parser.getAttributeValue(null, name);
+        return str != null ? Boolean.valueOf(str) : defaultValue;
+    }
+
+    private static void readDisplay(XmlPullParser parser, FileData fileData)
+            throws NumberFormatException, XmlPullParserException, IOException {
+        String name = parser.getAttributeValue(null, "name");
+        if (name != null) {
+            SettingsEntry settingsEntry = new SettingsEntry();
+            settingsEntry.mWindowingMode = getIntAttribute(parser, "windowingMode",
+                    WindowConfiguration.WINDOWING_MODE_UNDEFINED /* defaultValue */);
+            settingsEntry.mUserRotationMode = getIntegerAttribute(parser, "userRotationMode",
+                    null /* defaultValue */);
+            settingsEntry.mUserRotation = getIntegerAttribute(parser, "userRotation",
+                    null /* defaultValue */);
+            settingsEntry.mForcedWidth = getIntAttribute(parser, "forcedWidth",
+                    0 /* defaultValue */);
+            settingsEntry.mForcedHeight = getIntAttribute(parser, "forcedHeight",
+                    0 /* defaultValue */);
+            settingsEntry.mForcedDensity = getIntAttribute(parser, "forcedDensity",
+                    0 /* defaultValue */);
+            settingsEntry.mForcedScalingMode = getIntegerAttribute(parser, "forcedScalingMode",
+                    null /* defaultValue */);
+            settingsEntry.mRemoveContentMode = getIntAttribute(parser, "removeContentMode",
+                    REMOVE_CONTENT_MODE_UNDEFINED /* defaultValue */);
+            settingsEntry.mShouldShowWithInsecureKeyguard = getBooleanAttribute(parser,
+                    "shouldShowWithInsecureKeyguard", null /* defaultValue */);
+            settingsEntry.mShouldShowSystemDecors = getBooleanAttribute(parser,
+                    "shouldShowSystemDecors", null /* defaultValue */);
+            settingsEntry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme",
+                    null /* defaultValue */);
+            settingsEntry.mFixedToUserRotation = getIntegerAttribute(parser, "fixedToUserRotation",
+                    null /* defaultValue */);
+            settingsEntry.mIgnoreOrientationRequest = getBooleanAttribute(parser,
+                    "ignoreOrientationRequest", null /* defaultValue */);
+            fileData.mSettings.put(name, settingsEntry);
+        }
+        XmlUtils.skipCurrentTag(parser);
+    }
+
+    private static void readConfig(XmlPullParser parser, FileData fileData)
+            throws NumberFormatException,
+            XmlPullParserException, IOException {
+        fileData.mIdentifierType = getIntAttribute(parser, "identifier",
+                IDENTIFIER_UNIQUE_ID);
+        XmlUtils.skipCurrentTag(parser);
+    }
+
+    private static void writeSettings(WritableSettingsStorage storage, FileData data) {
+        OutputStream stream;
+        try {
+            stream = storage.startWrite();
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to write display settings: " + e);
+            return;
+        }
+
+        boolean success = false;
+        try {
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(stream, StandardCharsets.UTF_8.name());
+            out.startDocument(null, true);
+
+            out.startTag(null, "display-settings");
+
+            out.startTag(null, "config");
+            out.attribute(null, "identifier",
+                    Integer.toString(data.mIdentifierType));
+            out.endTag(null, "config");
+
+            for (Map.Entry<String, SettingsEntry> entry
+                    : data.mSettings.entrySet()) {
+                String displayIdentifier = entry.getKey();
+                SettingsEntry settingsEntry = entry.getValue();
+                if (settingsEntry.isEmpty()) {
+                    continue;
+                }
+
+                out.startTag(null, "display");
+                out.attribute(null, "name", displayIdentifier);
+                if (settingsEntry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+                    out.attribute(null, "windowingMode",
+                            Integer.toString(settingsEntry.mWindowingMode));
+                }
+                if (settingsEntry.mUserRotationMode != null) {
+                    out.attribute(null, "userRotationMode",
+                            settingsEntry.mUserRotationMode.toString());
+                }
+                if (settingsEntry.mUserRotation != null) {
+                    out.attribute(null, "userRotation",
+                            settingsEntry.mUserRotation.toString());
+                }
+                if (settingsEntry.mForcedWidth != 0 && settingsEntry.mForcedHeight != 0) {
+                    out.attribute(null, "forcedWidth",
+                            Integer.toString(settingsEntry.mForcedWidth));
+                    out.attribute(null, "forcedHeight",
+                            Integer.toString(settingsEntry.mForcedHeight));
+                }
+                if (settingsEntry.mForcedDensity != 0) {
+                    out.attribute(null, "forcedDensity",
+                            Integer.toString(settingsEntry.mForcedDensity));
+                }
+                if (settingsEntry.mForcedScalingMode != null) {
+                    out.attribute(null, "forcedScalingMode",
+                            settingsEntry.mForcedScalingMode.toString());
+                }
+                if (settingsEntry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
+                    out.attribute(null, "removeContentMode",
+                            Integer.toString(settingsEntry.mRemoveContentMode));
+                }
+                if (settingsEntry.mShouldShowWithInsecureKeyguard != null) {
+                    out.attribute(null, "shouldShowWithInsecureKeyguard",
+                            settingsEntry.mShouldShowWithInsecureKeyguard.toString());
+                }
+                if (settingsEntry.mShouldShowSystemDecors != null) {
+                    out.attribute(null, "shouldShowSystemDecors",
+                            settingsEntry.mShouldShowSystemDecors.toString());
+                }
+                if (settingsEntry.mShouldShowIme != null) {
+                    out.attribute(null, "shouldShowIme",
+                            settingsEntry.mShouldShowIme.toString());
+                }
+                if (settingsEntry.mFixedToUserRotation != null) {
+                    out.attribute(null, "fixedToUserRotation",
+                            settingsEntry.mFixedToUserRotation.toString());
+                }
+                if (settingsEntry.mIgnoreOrientationRequest != null) {
+                    out.attribute(null, "ignoreOrientationRequest",
+                            settingsEntry.mIgnoreOrientationRequest.toString());
+                }
+                out.endTag(null, "display");
+            }
+
+            out.endTag(null, "display-settings");
+            out.endDocument();
+            success = true;
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to write display window settings.", e);
+        } finally {
+            storage.finishWrite(stream, success);
+        }
+    }
+
+    private static final class FileData {
+        int mIdentifierType;
+        final Map<String, SettingsEntry> mSettings = new HashMap<>();
+
+        @Override
+        public String toString() {
+            return "FileData{"
+                    + "mIdentifierType=" + mIdentifierType
+                    + ", mSettings=" + mSettings
+                    + '}';
+        }
+    }
+
+    private static final class AtomicFileStorage implements WritableSettingsStorage {
+        private final AtomicFile mAtomicFile;
+
+        AtomicFileStorage(@NonNull AtomicFile atomicFile) {
+            mAtomicFile = atomicFile;
+        }
+
+        @Override
+        public InputStream openRead() throws FileNotFoundException {
+            return mAtomicFile.openRead();
+        }
+
+        @Override
+        public OutputStream startWrite() throws IOException {
+            return mAtomicFile.startWrite();
+        }
+
+        @Override
+        public void finishWrite(OutputStream os, boolean success) {
+            if (!(os instanceof FileOutputStream)) {
+                throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
+            }
+            FileOutputStream fos = (FileOutputStream) os;
+            if (success) {
+                mAtomicFile.finishWrite(fos);
+            } else {
+                mAtomicFile.failWrite(fos);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c806c94..33b3e59 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -44,6 +44,7 @@
 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.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -197,7 +198,6 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
-import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
@@ -576,6 +576,7 @@
     final PackageManagerInternal mPmInternal;
     private final TestUtilityService mTestUtilityService;
 
+    final DisplayWindowSettingsProvider mDisplayWindowSettingsProvider;
     final DisplayWindowSettings mDisplayWindowSettings;
 
     /** If the system should display notifications for apps displaying an alert window. */
@@ -799,6 +800,8 @@
                 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);
 
         public SettingsObserver() {
             super(new Handler());
@@ -823,6 +826,8 @@
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(mIgnoreVendorDisplaySettingsUri, false, this,
+                    UserHandle.USER_ALL);
         }
 
         @Override
@@ -866,6 +871,11 @@
                 return;
             }
 
+            if (mIgnoreVendorDisplaySettingsUri.equals(uri)) {
+                updateIgnoreVendorDisplaySettings();
+                return;
+            }
+
             @UpdateAnimationScaleMode
             final int mode;
             if (mWindowAnimationScaleUri.equals(uri)) {
@@ -955,6 +965,19 @@
 
             mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
         }
+
+        void updateIgnoreVendorDisplaySettings() {
+            final ContentResolver resolver = mContext.getContentResolver();
+            final boolean ignoreVendorSettings = Settings.Global.getInt(resolver,
+                    DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+            synchronized (mGlobalLock) {
+                mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorSettings);
+                mRoot.forAllDisplays(display -> {
+                    mDisplayWindowSettings.applySettingsToDisplayLocked(display);
+                    display.reconfigureDisplayLocked();
+                });
+            }
+        }
     }
 
     private void setShadowRenderer() {
@@ -1213,7 +1236,6 @@
         mSurfaceFactory = surfaceFactory;
         mTransaction = mTransactionFactory.get();
 
-        mDisplayWindowSettings = new DisplayWindowSettings(this);
         mPolicy = policy;
         mAnimator = new WindowAnimator(this);
         mRoot = new RootWindowContainer(this);
@@ -1312,6 +1334,12 @@
         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;
+        mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider();
+        mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorDisplaySettings);
+        mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider);
+
         IntentFilter filter = new IntentFilter();
         // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
         filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
new file mode 100644
index 0000000..b346bb8
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.platform.test.annotations.Presubmit;
+import android.util.Xml;
+import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Tests for the {@link DisplayWindowSettingsProvider} class.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:DisplayWindowSettingsProviderTests
+ */
+@SmallTest
+@Presubmit
+@WindowTestsBase.UseTestDisplay
+@RunWith(WindowTestRunner.class)
+public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
+    private static final int DISPLAY_PORT = 0xFF;
+    private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
+
+    private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
+
+    private TestStorage mBaseSettingsStorage;
+    private TestStorage mOverrideSettingsStorage;
+
+    private DisplayContent mPrimaryDisplay;
+    private DisplayContent mSecondaryDisplay;
+
+    @Before
+    public void setUp() throws Exception {
+        deleteRecursively(TEST_FOLDER);
+
+        mBaseSettingsStorage = new TestStorage();
+        mOverrideSettingsStorage = new TestStorage();
+
+        mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
+        mSecondaryDisplay = mDisplayContent;
+        assertNotEquals(Display.DEFAULT_DISPLAY, mSecondaryDisplay.getDisplayId());
+    }
+
+    @After
+    public void tearDown() {
+        deleteRecursively(TEST_FOLDER);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage() {
+        final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+        prepareOverrideDisplaySettings(displayIdentifier);
+
+        SettingsEntry expectedSettings = new SettingsEntry();
+        expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+        readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_LegacyDisplayId() {
+        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
+        prepareOverrideDisplaySettings(displayIdentifier);
+
+        SettingsEntry expectedSettings = new SettingsEntry();
+        expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+        readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_LegacyDisplayId_UpdateAfterAccess()
+            throws Exception {
+        // Store display settings with legacy display identifier.
+        final DisplayInfo mPrimaryDisplayInfo = mPrimaryDisplay.getDisplayInfo();
+        final String displayIdentifier = mPrimaryDisplayInfo.name;
+        prepareOverrideDisplaySettings(displayIdentifier);
+
+        // Update settings with new value, should trigger write to injector.
+        DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+                mBaseSettingsStorage, mOverrideSettingsStorage);
+        SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo);
+        overrideSettings.mForcedDensity = 200;
+        provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings);
+        assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+        // Verify that display identifier was updated.
+        final String newDisplayIdentifier = getStoredDisplayAttributeValue(
+                mOverrideSettingsStorage, "name");
+        assertEquals("Display identifier must be updated to use uniqueId",
+                mPrimaryDisplayInfo.uniqueId, newDisplayIdentifier);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
+        final DisplayAddress.Physical displayAddress =
+                DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
+        mPrimaryDisplay.getDisplayInfo().address = displayAddress;
+
+        final String displayIdentifier = "port:" + DISPLAY_PORT;
+        prepareOverrideDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+        SettingsEntry expectedSettings = new SettingsEntry();
+        expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+        readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_UsePortAsId_IncorrectAddress() {
+        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().uniqueId;
+        prepareOverrideDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+        mPrimaryDisplay.getDisplayInfo().address = DisplayAddress.fromPhysicalDisplayId(123456);
+
+        // Verify that the entry is not matched and default settings are returned instead.
+        SettingsEntry expectedSettings = new SettingsEntry();
+        readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+    }
+
+    @Test
+    public void testWritingDisplaySettingsToStorage() throws Exception {
+        final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
+
+        // Write some settings to storage.
+        DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+                mBaseSettingsStorage, mOverrideSettingsStorage);
+        SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
+        overrideSettings.mShouldShowSystemDecors = true;
+        overrideSettings.mShouldShowIme = true;
+        provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+        assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+        // Verify that settings were stored correctly.
+        assertEquals("Attribute value must be stored", secondaryDisplayInfo.uniqueId,
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+    }
+
+    @Test
+    public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
+        prepareOverrideDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
+
+        // Store config to use port as identifier.
+        final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
+        final DisplayAddress.Physical displayAddress =
+                DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
+        secondaryDisplayInfo.address = displayAddress;
+
+        // Write some settings to storage.
+        DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+                mBaseSettingsStorage, mOverrideSettingsStorage);
+        SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
+        overrideSettings.mShouldShowSystemDecors = true;
+        overrideSettings.mShouldShowIme = true;
+        provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+        assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+        // Verify that settings were stored correctly.
+        assertEquals("Attribute value must be stored", "port:" + DISPLAY_PORT,
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+    }
+
+    /**
+     * Prepares display settings and stores in {@link #mOverrideSettingsStorage}. Uses provided
+     * display identifier and stores windowingMode=WINDOWING_MODE_PINNED.
+     */
+    private void prepareOverrideDisplaySettings(String displayIdentifier) {
+        prepareOverrideDisplaySettings(displayIdentifier, false /* usePortAsId */);
+    }
+
+    private void prepareOverrideDisplaySettings(String displayIdentifier, boolean usePortAsId) {
+        String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<display-settings>\n";
+        if (usePortAsId) {
+            contents += "  <config identifier=\"1\"/>\n";
+        }
+        if (displayIdentifier != null) {
+            contents += "  <display\n"
+                    + "    name=\"" + displayIdentifier + "\"\n"
+                    + "    windowingMode=\"" + WINDOWING_MODE_PINNED + "\"/>\n";
+        }
+        contents += "</display-settings>\n";
+
+        final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+        mOverrideSettingsStorage.setReadStream(is);
+    }
+
+    private void readAndAssertExpectedSettings(DisplayContent displayContent,
+            SettingsEntry expectedSettings) {
+        final DisplayWindowSettingsProvider provider =
+                new DisplayWindowSettingsProvider(mBaseSettingsStorage, mOverrideSettingsStorage);
+        assertEquals(expectedSettings, provider.getSettings(displayContent.getDisplayInfo()));
+    }
+
+    @Nullable
+    private String getStoredDisplayAttributeValue(TestStorage storage, String attr)
+            throws Exception {
+        try (InputStream stream = storage.openRead()) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                // Do nothing.
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new IllegalStateException("no start tag found");
+            }
+
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals("display")) {
+                    return parser.getAttributeValue(null, attr);
+                }
+            }
+        } finally {
+            storage.closeRead();
+        }
+        return null;
+    }
+
+    private static boolean deleteRecursively(File file) {
+        boolean fullyDeleted = true;
+        if (file.isFile()) {
+            return file.delete();
+        } else if (file.isDirectory()) {
+            final File[] files = file.listFiles();
+            for (File child : files) {
+                fullyDeleted &= deleteRecursively(child);
+            }
+            fullyDeleted &= file.delete();
+        }
+        return fullyDeleted;
+    }
+
+    /** In-memory storage implementation. */
+    public class TestStorage implements DisplayWindowSettingsProvider.WritableSettingsStorage {
+        private InputStream mReadStream;
+        private ByteArrayOutputStream mWriteStream;
+
+        private boolean mWasSuccessful;
+
+        /**
+         * Returns input stream for reading. By default tries forward the output stream if previous
+         * write was successful.
+         * @see #closeRead()
+         */
+        @Override
+        public InputStream openRead() throws FileNotFoundException {
+            if (mReadStream == null && mWasSuccessful) {
+                mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
+            }
+            if (mReadStream == null) {
+                throw new FileNotFoundException();
+            }
+            if (mReadStream.markSupported()) {
+                mReadStream.mark(Integer.MAX_VALUE);
+            }
+            return mReadStream;
+        }
+
+        /** Must be called after each {@link #openRead} to reset the position in the stream. */
+        void closeRead() throws IOException {
+            if (mReadStream == null) {
+                throw new FileNotFoundException();
+            }
+            if (mReadStream.markSupported()) {
+                mReadStream.reset();
+            }
+            mReadStream = null;
+        }
+
+        /**
+         * Creates new or resets existing output stream for write. Automatically closes previous
+         * read stream, since following reads should happen based on this new write.
+         */
+        @Override
+        public OutputStream startWrite() throws IOException {
+            if (mWriteStream == null) {
+                mWriteStream = new ByteArrayOutputStream();
+            } else {
+                mWriteStream.reset();
+            }
+            if (mReadStream != null) {
+                closeRead();
+            }
+            return mWriteStream;
+        }
+
+        @Override
+        public void finishWrite(OutputStream os, boolean success) {
+            mWasSuccessful = success;
+            try {
+                os.close();
+            } catch (IOException e) {
+                // This method can't throw IOException since the super implementation doesn't, so
+                // we just wrap it in a RuntimeException so we end up crashing the test all the
+                // same.
+                throw new RuntimeException(e);
+            }
+        }
+
+        /** Overrides the read stream of the injector. By default it uses current write stream. */
+        private void setReadStream(InputStream is) {
+            mReadStream = is;
+        }
+
+        private boolean wasWriteSuccessful() {
+            return mWasSuccessful;
+        }
+    }
+}
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 a3d3739a..2ca5583 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -17,15 +17,12 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
 
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -40,12 +37,11 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.eq;
 
+import android.annotation.NonNull;
 import android.app.WindowConfiguration;
 import android.content.res.Configuration;
 import android.platform.test.annotations.Presubmit;
-import android.util.Xml;
 import android.view.Display;
-import android.view.DisplayAddress;
 import android.view.DisplayInfo;
 import android.view.Surface;
 
@@ -53,21 +49,14 @@
 
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Tests for the {@link DisplayWindowSettings} class.
@@ -80,12 +69,8 @@
 @WindowTestsBase.UseTestDisplay
 @RunWith(WindowTestRunner.class)
 public class DisplayWindowSettingsTests extends WindowTestsBase {
-
-    private static final int DISPLAY_PORT = 0xFF;
-    private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
-
-    private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
-    private DisplayWindowSettings mTarget;
+    private TestSettingsProvider mSettingsProvider;
+    private DisplayWindowSettings mDisplayWindowSettings;
 
     private DisplayInfo mPrivateDisplayInfo;
 
@@ -93,18 +78,19 @@
     private DisplayContent mSecondaryDisplay;
     private DisplayContent mPrivateDisplay;
 
-    private TestStorage mStorage;
-
     @Before
     public void setUp() throws Exception {
-        deleteRecursively(TEST_FOLDER);
-
+        // TODO(b/121296525): We may want to restore other display settings (not only overscans in
+        // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
+        // values after each test finishes, since we are going to reuse a singleton
+        // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
+        // (b/113239988).
         mWm.mAtmService.mSupportsFreeformWindowManagement = false;
         mWm.setIsPc(false);
         mWm.setForceDesktopModeOnExternalDisplays(false);
 
-        mStorage = new TestStorage();
-        mTarget = new DisplayWindowSettings(mWm, mStorage);
+        mSettingsProvider = new TestSettingsProvider();
+        mDisplayWindowSettings = new DisplayWindowSettings(mWm, mSettingsProvider);
 
         mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
         mSecondaryDisplay = mDisplayContent;
@@ -117,20 +103,9 @@
         assertNotEquals(mSecondaryDisplay.getDisplayId(), mPrivateDisplay.getDisplayId());
     }
 
-    @After
-    public void tearDown() {
-        deleteRecursively(TEST_FOLDER);
-
-        // TODO(b/121296525): We may want to restore other display settings (not only overscans in
-        // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
-        // values after each test finishes, since we are going to reuse a singleton
-        // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
-        // (b/113239988).
-    }
-
     @Test
     public void testPrimaryDisplayDefaultToFullscreen_NoFreeformSupport() {
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
                 mPrimaryDisplay.getWindowingMode());
@@ -140,7 +115,7 @@
     public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
 
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
                 mPrimaryDisplay.getWindowingMode());
@@ -151,7 +126,7 @@
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setForceDesktopModeOnExternalDisplays(true);
 
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
                 mPrimaryDisplay.getWindowingMode());
@@ -162,20 +137,19 @@
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setIsPc(true);
 
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
-        assertEquals(WINDOWING_MODE_FREEFORM,
-                mPrimaryDisplay.getWindowingMode());
+        assertEquals(WINDOWING_MODE_FREEFORM, mPrimaryDisplay.getWindowingMode());
     }
 
     @Test
     public void testPrimaryDisplayUpdateToFreeform_HasFreeformSupport_IsPc() {
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setIsPc(true);
 
-        mTarget.updateSettingsForDisplay(mPrimaryDisplay);
+        mDisplayWindowSettings.updateSettingsForDisplay(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
                 mPrimaryDisplay.getWindowingMode());
@@ -183,7 +157,7 @@
 
     @Test
     public void testSecondaryDisplayDefaultToFullscreen_NoFreeformSupport() {
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
                 mSecondaryDisplay.getWindowingMode());
@@ -193,7 +167,7 @@
     public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() {
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
 
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
                 mSecondaryDisplay.getWindowingMode());
@@ -204,7 +178,7 @@
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setForceDesktopModeOnExternalDisplays(true);
 
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WINDOWING_MODE_FREEFORM,
                 mSecondaryDisplay.getWindowingMode());
@@ -215,7 +189,7 @@
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setIsPc(true);
 
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WINDOWING_MODE_FREEFORM,
                 mSecondaryDisplay.getWindowingMode());
@@ -228,7 +202,7 @@
         final int originalDensity = mSecondaryDisplay.mBaseDisplayDensity;
         final boolean originalScalingDisabled = mSecondaryDisplay.mDisplayScalingDisabled;
 
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(originalWidth, mSecondaryDisplay.mBaseDisplayWidth);
         assertEquals(originalHeight, mSecondaryDisplay.mBaseDisplayHeight);
@@ -245,8 +219,9 @@
             return null;
         }).when(mWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any());
 
-        mTarget.setForcedSize(mSecondaryDisplay, 1000 /* width */, 2000 /* height */);
-        applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+        mDisplayWindowSettings.setForcedSize(mSecondaryDisplay, 1000 /* width */,
+                2000 /* height */);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(1000 /* width */, mSecondaryDisplay.mBaseDisplayWidth);
         assertEquals(2000 /* height */, mSecondaryDisplay.mBaseDisplayHeight);
@@ -258,8 +233,9 @@
 
     @Test
     public void testSetForcedDensity() {
-        mTarget.setForcedDensity(mSecondaryDisplay, 600 /* density */, 0 /* userId */);
-        applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+        mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay, 600 /* density */,
+                0 /* userId */);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity);
 
@@ -270,8 +246,9 @@
 
     @Test
     public void testSetForcedScalingMode() {
-        mTarget.setForcedScalingMode(mSecondaryDisplay, DisplayContent.FORCE_SCALING_MODE_DISABLED);
-        applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+        mDisplayWindowSettings.setForcedScalingMode(mSecondaryDisplay,
+                DisplayContent.FORCE_SCALING_MODE_DISABLED);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertTrue(mSecondaryDisplay.mDisplayScalingDisabled);
 
@@ -282,7 +259,7 @@
 
     @Test
     public void testDefaultToFreeUserRotation() {
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
         assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, rotation.getUserRotationMode());
@@ -291,7 +268,7 @@
 
     @Test
     public void testDefaultTo0DegRotation() {
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(Surface.ROTATION_0, mSecondaryDisplay.getDisplayRotation().getUserRotation());
     }
@@ -299,70 +276,68 @@
     @Test
     public void testPrivateDisplayDefaultToDestroyContent() {
         assertEquals(REMOVE_CONTENT_MODE_DESTROY,
-                mTarget.getRemoveContentModeLocked(mPrivateDisplay));
+                mDisplayWindowSettings.getRemoveContentModeLocked(mPrivateDisplay));
     }
 
     @Test
     public void testPublicDisplayDefaultToMoveToPrimary() {
         assertEquals(REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
-                mTarget.getRemoveContentModeLocked(mSecondaryDisplay));
+                mDisplayWindowSettings.getRemoveContentModeLocked(mSecondaryDisplay));
     }
 
     @Test
     public void testDefaultToNotShowWithInsecureKeyguard() {
-        assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
-        assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
+        assertFalse(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
+        assertFalse(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
     }
 
-    @Test
+    @Test(expected = IllegalArgumentException.class)
     public void testPublicDisplayNotAllowSetShouldShowWithInsecureKeyguard() {
-        mTarget.setShouldShowWithInsecureKeyguardLocked(mSecondaryDisplay, true);
-
-        assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
+        mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(mSecondaryDisplay, true);
     }
 
     @Test
     public void testPrivateDisplayAllowSetShouldShowWithInsecureKeyguard() {
-        mTarget.setShouldShowWithInsecureKeyguardLocked(mPrivateDisplay, true);
+        mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(mPrivateDisplay, true);
 
-        assertTrue(mTarget.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
+        assertTrue(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
     }
 
     @Test
     public void testPrimaryDisplayShouldShowSystemDecors() {
-        assertTrue(mTarget.shouldShowSystemDecorsLocked(mPrimaryDisplay));
+        assertTrue(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mPrimaryDisplay));
 
-        mTarget.setShouldShowSystemDecorsLocked(mPrimaryDisplay, false);
+        mDisplayWindowSettings.setShouldShowSystemDecorsLocked(mPrimaryDisplay, false);
 
         // Default display should show system decors
-        assertTrue(mTarget.shouldShowSystemDecorsLocked(mPrimaryDisplay));
+        assertTrue(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mPrimaryDisplay));
     }
 
     @Test
     public void testSecondaryDisplayDefaultToNotShowSystemDecors() {
-        assertFalse(mTarget.shouldShowSystemDecorsLocked(mSecondaryDisplay));
+        assertFalse(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mSecondaryDisplay));
     }
 
     @Test
     public void testPrimaryDisplayShouldShowIme() {
-        assertTrue(mTarget.shouldShowImeLocked(mPrimaryDisplay));
+        assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
 
-        mTarget.setShouldShowImeLocked(mPrimaryDisplay, false);
+        mDisplayWindowSettings.setShouldShowImeLocked(mPrimaryDisplay, false);
 
-        assertTrue(mTarget.shouldShowImeLocked(mPrimaryDisplay));
+        assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
     }
 
     @Test
     public void testSecondaryDisplayDefaultToNotShowIme() {
-        assertFalse(mTarget.shouldShowImeLocked(mSecondaryDisplay));
+        assertFalse(mDisplayWindowSettings.shouldShowImeLocked(mSecondaryDisplay));
     }
 
     @Test
-    public void testPersistUserRotationModeInSameInstance() {
-        mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
-                Surface.ROTATION_90);
+    public void testSetUserRotationMode() {
+        mDisplayWindowSettings.setUserRotation(mSecondaryDisplay,
+                WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_90);
 
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
@@ -370,48 +345,25 @@
     }
 
     @Test
-    public void testPersistUserRotationInSameInstance() {
-        mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
-                Surface.ROTATION_90);
+    public void testSetUserRotation() {
+        mDisplayWindowSettings.setUserRotation(mSecondaryDisplay,
+                WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_90);
 
-        mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(Surface.ROTATION_90, mSecondaryDisplay.getDisplayRotation().getUserRotation());
     }
 
     @Test
-    public void testPersistUserRotationModeAcrossInstances() {
-        mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
-                Surface.ROTATION_270);
-
-        applySettingsToDisplayByNewInstance(mSecondaryDisplay);
-
-        final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
-        assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
-        assertTrue(rotation.isRotationFrozen());
-    }
-
-    @Test
-    public void testPersistUserRotationAcrossInstances() {
-        mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
-                Surface.ROTATION_270);
-
-        applySettingsToDisplayByNewInstance(mSecondaryDisplay);
-
-        assertEquals(Surface.ROTATION_270,
-                mSecondaryDisplay.getDisplayRotation().getUserRotation());
-    }
-
-    @Test
     public void testFixedToUserRotationDefault() {
-        mTarget.setUserRotation(mPrimaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
-                Surface.ROTATION_0);
+        mDisplayWindowSettings.setUserRotation(mPrimaryDisplay,
+                WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_0);
 
         final DisplayRotation displayRotation = mock(DisplayRotation.class);
         spyOn(mPrimaryDisplay);
         doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
 
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         verify(displayRotation).restoreSettings(anyInt(), anyInt(),
                 eq(FIXED_TO_USER_ROTATION_DEFAULT));
@@ -419,13 +371,14 @@
 
     @Test
     public void testSetFixedToUserRotationDisabled() {
-        mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_DISABLED);
+        mDisplayWindowSettings.setFixedToUserRotation(mPrimaryDisplay,
+                FIXED_TO_USER_ROTATION_DISABLED);
 
         final DisplayRotation displayRotation = mock(DisplayRotation.class);
         spyOn(mPrimaryDisplay);
         doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
 
-        applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         verify(displayRotation).restoreSettings(anyInt(), anyInt(),
                 eq(FIXED_TO_USER_ROTATION_DISABLED));
@@ -433,120 +386,20 @@
 
     @Test
     public void testSetFixedToUserRotationEnabled() {
-        mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_ENABLED);
+        mDisplayWindowSettings.setFixedToUserRotation(mPrimaryDisplay,
+                FIXED_TO_USER_ROTATION_ENABLED);
 
         final DisplayRotation displayRotation = mock(DisplayRotation.class);
         spyOn(mPrimaryDisplay);
         doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
 
-        applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         verify(displayRotation).restoreSettings(anyInt(), anyInt(),
                 eq(FIXED_TO_USER_ROTATION_ENABLED));
     }
 
     @Test
-    public void testReadingDisplaySettingsFromStorage() {
-        final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
-        prepareDisplaySettings(displayIdentifier);
-
-        readAndAssertDisplaySettings(mPrimaryDisplay);
-    }
-
-    @Test
-    public void testReadingDisplaySettingsFromStorage_LegacyDisplayId() {
-        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
-        prepareDisplaySettings(displayIdentifier);
-
-        readAndAssertDisplaySettings(mPrimaryDisplay);
-    }
-
-    @Test
-    public void testReadingDisplaySettingsFromStorage_LegacyDisplayId_UpdateAfterAccess()
-            throws Exception {
-        // Store display settings with legacy display identifier.
-        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
-        prepareDisplaySettings(displayIdentifier);
-
-        // Update settings with new value, should trigger write to injector.
-        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
-        settings.setRemoveContentModeLocked(mPrimaryDisplay, REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY);
-        assertEquals("Settings value must be updated", REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
-                settings.getRemoveContentModeLocked(mPrimaryDisplay));
-        assertTrue(mStorage.wasWriteSuccessful());
-
-        // Verify that display identifier was updated.
-        final String newDisplayIdentifier = getStoredDisplayAttributeValue("name");
-        assertEquals("Display identifier must be updated to use uniqueId",
-                mPrimaryDisplay.getDisplayInfo().uniqueId, newDisplayIdentifier);
-    }
-
-    @Test
-    public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
-        final DisplayAddress.Physical displayAddress =
-                DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
-        mPrimaryDisplay.getDisplayInfo().address = displayAddress;
-
-        final String displayIdentifier = "port:" + DISPLAY_PORT;
-        prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
-
-        readAndAssertDisplaySettings(mPrimaryDisplay);
-    }
-
-    @Test
-    public void testReadingDisplaySettingsFromStorage_UsePortAsId_IncorrectAddress() {
-        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().uniqueId;
-        prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
-
-        mPrimaryDisplay.getDisplayInfo().address = DisplayAddress.fromPhysicalDisplayId(123456);
-
-        // Verify that the entry is not matched and default settings are returned instead.
-        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm);
-        assertNotEquals("Default setting must be returned for new entry",
-                WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(mPrimaryDisplay));
-    }
-
-    @Test
-    public void testWritingDisplaySettingsToStorage() throws Exception {
-        // Write some settings to storage.
-        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
-        settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
-        settings.setShouldShowImeLocked(mSecondaryDisplay, true);
-        assertTrue(mStorage.wasWriteSuccessful());
-
-        // Verify that settings were stored correctly.
-        assertEquals("Attribute value must be stored", mSecondaryDisplay.getDisplayInfo().uniqueId,
-                getStoredDisplayAttributeValue("name"));
-        assertEquals("Attribute value must be stored", "true",
-                getStoredDisplayAttributeValue("shouldShowSystemDecors"));
-        assertEquals("Attribute value must be stored", "true",
-                getStoredDisplayAttributeValue("shouldShowIme"));
-    }
-
-    @Test
-    public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
-        // Store config to use port as identifier.
-        final DisplayAddress.Physical displayAddress =
-                DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
-        mSecondaryDisplay.getDisplayInfo().address = displayAddress;
-        prepareDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
-
-        // Write some settings.
-        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
-        settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
-        settings.setShouldShowImeLocked(mSecondaryDisplay, true);
-        assertTrue(mStorage.wasWriteSuccessful());
-
-        // Verify that settings were stored correctly.
-        assertEquals("Attribute value must be stored", "port:" + DISPLAY_PORT,
-                getStoredDisplayAttributeValue("name"));
-        assertEquals("Attribute value must be stored", "true",
-                getStoredDisplayAttributeValue("shouldShowSystemDecors"));
-        assertEquals("Attribute value must be stored", "true",
-                getStoredDisplayAttributeValue("shouldShowIme"));
-    }
-
-    @Test
     public void testShouldShowImeWithinForceDesktopMode() {
         try {
             // Presume display enabled force desktop mode from developer options.
@@ -567,14 +420,13 @@
     public void testDisplayWindowSettingsAppliedOnDisplayReady() {
         // Set forced densities for two displays in DisplayWindowSettings
         final DisplayContent dc = createMockSimulatedDisplay();
-        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
-        settings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
-        settings.setForcedDensity(dc, 456, 0 /* userId */);
+        mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
+        mDisplayWindowSettings.setForcedDensity(dc, 456, 0 /* userId */);
 
         // Apply settings to displays - the settings will be stored, but config will not be
         // recalculated immediately.
-        settings.applySettingsToDisplayLocked(mPrimaryDisplay);
-        settings.applySettingsToDisplayLocked(dc);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
+        mDisplayWindowSettings.applySettingsToDisplayLocked(dc);
         assertFalse(mPrimaryDisplay.mWaitingForConfig);
         assertFalse(dc.mWaitingForConfig);
 
@@ -589,173 +441,34 @@
         assertEquals(456, config.densityDpi);
     }
 
-    /**
-     * Prepares display settings and stores in {@link #mStorage}. Uses provided display identifier
-     * and stores windowingMode=WINDOWING_MODE_PINNED.
-     */
-    private void prepareDisplaySettings(String displayIdentifier) {
-        prepareDisplaySettings(displayIdentifier, false /* usePortAsId */);
-    }
+    public final class TestSettingsProvider implements DisplayWindowSettings.SettingsProvider {
+        Map<DisplayInfo, SettingsEntry> mOverrideSettingsCache = new HashMap<>();
 
-    private void prepareDisplaySettings(String displayIdentifier, boolean usePortAsId) {
-        String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
-                + "<display-settings>\n";
-        if (usePortAsId) {
-            contents += "  <config identifier=\"1\"/>\n";
-        }
-        if (displayIdentifier != null) {
-            contents += "  <display\n"
-                    + "    name=\"" + displayIdentifier + "\"\n"
-                    + "    windowingMode=\"" + WINDOWING_MODE_PINNED + "\"/>\n";
-        }
-        contents += "</display-settings>\n";
-
-        final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
-        mStorage.setReadStream(is);
-    }
-
-    private void readAndAssertDisplaySettings(DisplayContent displayContent) {
-        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
-        assertEquals("Stored setting must be read",
-                WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(displayContent));
-        assertEquals("Not stored setting must be set to default value",
-                REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
-                settings.getRemoveContentModeLocked(displayContent));
-    }
-
-    private String getStoredDisplayAttributeValue(String attr) throws Exception {
-        try (InputStream stream = mStorage.openRead()) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(stream, StandardCharsets.UTF_8.name());
-            int type;
-            while ((type = parser.next()) != XmlPullParser.START_TAG
-                    && type != XmlPullParser.END_DOCUMENT) {
-                // Do nothing.
-            }
-
-            if (type != XmlPullParser.START_TAG) {
-                throw new IllegalStateException("no start tag found");
-            }
-
-            int outerDepth = parser.getDepth();
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-
-                String tagName = parser.getName();
-                if (tagName.equals("display")) {
-                    return parser.getAttributeValue(null, attr);
-                }
-            }
-        } finally {
-            mStorage.closeRead();
-        }
-        return null;
-    }
-
-    /**
-     * This method helps to ensure read and write persistent settings successfully because the
-     * constructor of {@link DisplayWindowSettings} should read the persistent file from the given
-     * path that also means the previous state must be written correctly.
-     */
-    private void applySettingsToDisplayByNewInstance(DisplayContent display) {
-        // Assert that prior write completed successfully.
-        assertTrue(mStorage.wasWriteSuccessful());
-
-        // Read and apply settings.
-        new DisplayWindowSettings(mWm, mStorage).applySettingsToDisplayLocked(display);
-    }
-
-    private static boolean deleteRecursively(File file) {
-        boolean fullyDeleted = true;
-        if (file.isFile()) {
-            return file.delete();
-        } else if (file.isDirectory()) {
-            final File[] files = file.listFiles();
-            for (File child : files) {
-                fullyDeleted &= deleteRecursively(child);
-            }
-            fullyDeleted &= file.delete();
-        }
-        return fullyDeleted;
-    }
-
-    /** In-memory storage implementation. */
-    public class TestStorage implements DisplayWindowSettings.SettingPersister {
-        private InputStream mReadStream;
-        private ByteArrayOutputStream mWriteStream;
-
-        private boolean mWasSuccessful;
-
-        /**
-         * Returns input stream for reading. By default tries forward the output stream if previous
-         * write was successful.
-         * @see #closeRead()
-         */
         @Override
-        public InputStream openRead() throws FileNotFoundException {
-            if (mReadStream == null && mWasSuccessful) {
-                mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
-            }
-            if (mReadStream == null) {
-                throw new FileNotFoundException();
-            }
-            if (mReadStream.markSupported()) {
-                mReadStream.mark(Integer.MAX_VALUE);
-            }
-            return mReadStream;
-        }
-
-        /** Must be called after each {@link #openRead} to reset the position in the stream. */
-        void closeRead() throws IOException {
-            if (mReadStream == null) {
-                throw new FileNotFoundException();
-            }
-            if (mReadStream.markSupported()) {
-                mReadStream.reset();
-            }
-            mReadStream = null;
-        }
-
-        /**
-         * Creates new or resets existing output stream for write. Automatically closes previous
-         * read stream, since following reads should happen based on this new write.
-         */
-        @Override
-        public OutputStream startWrite() throws IOException {
-            if (mWriteStream == null) {
-                mWriteStream = new ByteArrayOutputStream();
-            } else {
-                mWriteStream.reset();
-            }
-            if (mReadStream != null) {
-                closeRead();
-            }
-            return mWriteStream;
+        public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+            return getOverrideSettings(info);
         }
 
         @Override
-        public void finishWrite(OutputStream os, boolean success) {
-            mWasSuccessful = success;
-            try {
-                os.close();
-            } catch (IOException e) {
-                // This method can't throw IOException since the super implementation doesn't, so
-                // we just wrap it in a RuntimeException so we end up crashing the test all the
-                // same.
-                throw new RuntimeException(e);
+        public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+            SettingsEntry result = new SettingsEntry();
+            SettingsEntry overrideSettings = mOverrideSettingsCache.get(info);
+            if (overrideSettings != null) {
+                result.setTo(overrideSettings);
             }
+            return result;
         }
 
-        /** Override the read stream of the injector. By default it uses current write stream. */
-        private void setReadStream(InputStream is) {
-            mReadStream = is;
-        }
+        @Override
+        public void updateOverrideSettings(@NonNull DisplayInfo info,
+                @NonNull SettingsEntry settings) {
+            SettingsEntry overrideSettings = mOverrideSettingsCache.get(info);
+            if (overrideSettings == null) {
+                overrideSettings = new SettingsEntry();
+                mOverrideSettingsCache.put(info, overrideSettings);
+            }
 
-        private boolean wasWriteSuccessful() {
-            return mWasSuccessful;
+            overrideSettings.setTo(settings);
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 6f5389d..740f605 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -296,6 +296,7 @@
         // Called when moving activity to pinned stack.
         doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
                 anyInt(), anyBoolean(), anyBoolean());
+        spyOn(mWmService.mDisplayWindowSettings);
 
         // Setup factory classes to prevent calls to native code.
         mTransaction = spy(StubTransaction.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 8d5363c..ba144dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -20,12 +20,16 @@
 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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.ContentResolver;
@@ -37,6 +41,9 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.List;
 
 /**
  * Test for {@link WindowManagerService.SettingsObserver}.
@@ -124,6 +131,36 @@
         }
     }
 
+    @Test
+    public void testEnabledIgnoreVendorDisplaySettings() {
+        try (SettingsSession ignoreVendorDisplaySettingsSession = new
+                SettingsSession(DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS)) {
+            final boolean ignoreVendorDisplaySettings =
+                    !ignoreVendorDisplaySettingsSession.getSetting();
+            final Uri ignoreVendorDisplaySettingUri =
+                    ignoreVendorDisplaySettingsSession.setSetting(ignoreVendorDisplaySettings);
+
+            clearInvocations(mWm.mRoot);
+            clearInvocations(mWm.mDisplayWindowSettings);
+
+            mWm.mSettingsObserver.onChange(false /* selfChange */, ignoreVendorDisplaySettingUri);
+
+            assertEquals(mWm.mDisplayWindowSettingsProvider.getVendorSettingsIgnored(),
+                    ignoreVendorDisplaySettings);
+
+            ArgumentCaptor<DisplayContent> captor =
+                    ArgumentCaptor.forClass(DisplayContent.class);
+            verify(mWm.mDisplayWindowSettings, times(mWm.mRoot.mChildren.size()))
+                    .applySettingsToDisplayLocked(captor.capture());
+            List<DisplayContent> configuredDisplays = captor.getAllValues();
+            for (DisplayContent dc : mWm.mRoot.mChildren) {
+                assertTrue(configuredDisplays.contains(dc));
+            }
+
+            verify(mWm.mRoot, atLeastOnce()).performSurfacePlacement();
+        }
+    }
+
     private class SettingsSession implements AutoCloseable {
 
         private static final int SETTING_VALUE_OFF = 0;