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;